1 # Based from "GDBus - GLib D-Bus Library":
3 # Copyright (C) 2008-2011 Red Hat, Inc.
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.
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.
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/>.
18 # Author: David Zeuthen <davidz@redhat.com>
20 import xml
.parsers
.expat
24 def __init__(self
, key
, value
):
32 def __init__(self
, name
, signature
):
34 self
.signature
= signature
41 def __init__(self
, name
, h_type_implies_unix_fd
=True):
43 self
.h_type_implies_unix_fd
= h_type_implies_unix_fd
49 self
.deprecated
= False
54 def __init__(self
, name
):
60 self
.deprecated
= False
64 def __init__(self
, name
, signature
, access
):
66 self
.signature
= signature
69 self
.arg
= Arg("value", self
.signature
)
70 self
.arg
.annotations
= self
.annotations
73 if self
.access
== "readwrite":
76 elif self
.access
== "read":
78 elif self
.access
== "write":
81 raise ValueError('Invalid access type "{}"'.format(self
.access
))
84 self
.deprecated
= False
85 self
.emits_changed_signal
= True
89 def __init__(self
, name
):
96 self
.doc_string_brief
= ""
98 self
.deprecated
= False
104 STATE_INTERFACE
= "interface"
105 STATE_METHOD
= "method"
106 STATE_SIGNAL
= "signal"
107 STATE_PROPERTY
= "property"
109 STATE_ANNOTATION
= "annotation"
110 STATE_IGNORED
= "ignored"
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
119 self
.parsed_interfaces
= []
120 self
._cur
_object
= None
122 self
.state
= DBusXMLParser
.STATE_TOP
123 self
.state_stack
= []
124 self
._cur
_object
= None
125 self
._cur
_object
_stack
= []
127 self
.doc_comment_last_symbol
= ""
129 self
._h
_type
_implies
_unix
_fd
= h_type_implies_unix_fd
131 self
._parser
.Parse(xml_data
)
133 COMMENT_STATE_BEGIN
= "begin"
134 COMMENT_STATE_PARAMS
= "params"
135 COMMENT_STATE_BODY
= "body"
136 COMMENT_STATE_SKIP
= "skip"
138 def handle_comment(self
, data
):
139 comment_state
= DBusXMLParser
.COMMENT_STATE_BEGIN
140 lines
= data
.split("\n")
148 if comment_state
== DBusXMLParser
.COMMENT_STATE_BEGIN
:
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
156 comment_state
= DBusXMLParser
.COMMENT_STATE_SKIP
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
170 body
+= orig_line
+ "\n"
172 param
= line
[1:colon_index
]
173 docs
= line
[colon_index
+ 2 :]
176 comment_state
= DBusXMLParser
.COMMENT_STATE_BODY
180 body
+= orig_line
+ "\n"
181 elif comment_state
== DBusXMLParser
.COMMENT_STATE_BODY
:
185 body
+= orig_line
+ "\n"
194 self
.doc_comment_last_symbol
= symbol
195 self
.doc_comment_params
= params
196 self
.doc_comment_body
= body
198 def handle_char_data(self
, data
):
199 # print 'char_data=%s'%data
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
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
224 self
.state
= DBusXMLParser
.STATE_IGNORED
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()
235 elif self
.state
== DBusXMLParser
.STATE_INTERFACE
:
236 if name
== DBusXMLParser
.STATE_METHOD
:
237 self
.state
= DBusXMLParser
.STATE_METHOD
239 attrs
["name"], h_type_implies_unix_fd
=self
._h
_type
_implies
_unix
_fd
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
259 self
.state
= DBusXMLParser
.STATE_IGNORED
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()
267 elif self
.state
== DBusXMLParser
.STATE_METHOD
:
268 if name
== DBusXMLParser
.STATE_ARG
:
269 self
.state
= DBusXMLParser
.STATE_ARG
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
)
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
288 self
.state
= DBusXMLParser
.STATE_IGNORED
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
[
301 elif self
.state
== DBusXMLParser
.STATE_SIGNAL
:
302 if name
== DBusXMLParser
.STATE_ARG
:
303 self
.state
= DBusXMLParser
.STATE_ARG
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
316 self
.state
= DBusXMLParser
.STATE_IGNORED
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
[
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
336 self
.state
= DBusXMLParser
.STATE_IGNORED
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
345 self
.state
= DBusXMLParser
.STATE_IGNORED
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
354 self
.state
= DBusXMLParser
.STATE_IGNORED
358 'Unhandled state "{}" while entering element with name "{}"'.format(
363 self
.state_stack
.append(old_state
)
364 self
._cur
_object
_stack
.append(old_cur_object
)
366 def handle_end_element(self
, name
):
367 self
.state
= self
.state_stack
.pop()
368 self
._cur
_object
= self
._cur
_object
_stack
.pop()
371 def parse_dbus_xml(xml_data
):
372 parser
= DBusXMLParser(xml_data
, True)
373 return parser
.parsed_interfaces