3 # GDBus - GLib D-Bus Library
5 # Copyright (C) 2008-2011 Red Hat, Inc.
7 # This library is free software; you can redistribute it and/or
8 # modify it under the terms of the GNU Lesser General Public
9 # License as published by the Free Software Foundation; either
10 # version 2 of the License, or (at your option) any later version.
12 # This library is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 # Lesser General Public License for more details.
17 # You should have received a copy of the GNU Lesser General
18 # Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
20 # Author: David Zeuthen <davidz@redhat.com>
23 import xml
.parsers
.expat
25 from . import dbustypes
30 STATE_INTERFACE
= 'interface'
31 STATE_METHOD
= 'method'
32 STATE_SIGNAL
= 'signal'
33 STATE_PROPERTY
= 'property'
35 STATE_ANNOTATION
= 'annotation'
36 STATE_IGNORED
= 'ignored'
38 def __init__(self
, xml_data
):
39 self
._parser
= xml
.parsers
.expat
.ParserCreate()
40 self
._parser
.CommentHandler
= self
.handle_comment
41 self
._parser
.CharacterDataHandler
= self
.handle_char_data
42 self
._parser
.StartElementHandler
= self
.handle_start_element
43 self
._parser
.EndElementHandler
= self
.handle_end_element
45 self
.parsed_interfaces
= []
46 self
._cur
_object
= None
48 self
.state
= DBusXMLParser
.STATE_TOP
50 self
._cur
_object
= None
51 self
._cur
_object
_stack
= []
53 self
.doc_comment_last_symbol
= ''
55 self
._parser
.Parse(xml_data
)
57 COMMENT_STATE_BEGIN
= 'begin'
58 COMMENT_STATE_PARAMS
= 'params'
59 COMMENT_STATE_BODY
= 'body'
60 COMMENT_STATE_SKIP
= 'skip'
61 def handle_comment(self
, data
):
62 comment_state
= DBusXMLParser
.COMMENT_STATE_BEGIN
;
63 lines
= data
.split('\n')
71 if comment_state
== DBusXMLParser
.COMMENT_STATE_BEGIN
:
73 colon_index
= line
.find(': ')
75 if line
.endswith(':'):
76 symbol
= line
[0:len(line
)-1]
77 comment_state
= DBusXMLParser
.COMMENT_STATE_PARAMS
79 comment_state
= DBusXMLParser
.COMMENT_STATE_SKIP
81 symbol
= line
[0:colon_index
]
82 rest_of_line
= line
[colon_index
+2:].strip()
83 if len(rest_of_line
) > 0:
84 body
+= '<para>' + rest_of_line
+ '</para>'
85 comment_state
= DBusXMLParser
.COMMENT_STATE_PARAMS
86 elif comment_state
== DBusXMLParser
.COMMENT_STATE_PARAMS
:
87 if line
.startswith('@'):
88 colon_index
= line
.find(': ')
90 comment_state
= DBusXMLParser
.COMMENT_STATE_BODY
94 body
+= orig_line
+ '\n'
96 param
= line
[1:colon_index
]
97 docs
= line
[colon_index
+ 2:]
100 comment_state
= DBusXMLParser
.COMMENT_STATE_BODY
105 body
+= orig_line
+ '\n'
106 elif comment_state
== DBusXMLParser
.COMMENT_STATE_BODY
:
111 body
+= orig_line
+ '\n'
120 self
.doc_comment_last_symbol
= symbol
121 self
.doc_comment_params
= params
122 self
.doc_comment_body
= body
124 def handle_char_data(self
, data
):
125 #print 'char_data=%s'%data
128 def handle_start_element(self
, name
, attrs
):
129 old_state
= self
.state
130 old_cur_object
= self
._cur
_object
131 if self
.state
== DBusXMLParser
.STATE_IGNORED
:
132 self
.state
= DBusXMLParser
.STATE_IGNORED
133 elif self
.state
== DBusXMLParser
.STATE_TOP
:
134 if name
== DBusXMLParser
.STATE_NODE
:
135 self
.state
= DBusXMLParser
.STATE_NODE
137 self
.state
= DBusXMLParser
.STATE_IGNORED
138 elif self
.state
== DBusXMLParser
.STATE_NODE
:
139 if name
== DBusXMLParser
.STATE_INTERFACE
:
140 self
.state
= DBusXMLParser
.STATE_INTERFACE
141 iface
= dbustypes
.Interface(attrs
['name'])
142 self
._cur
_object
= iface
143 self
.parsed_interfaces
.append(iface
)
144 elif name
== DBusXMLParser
.STATE_ANNOTATION
:
145 self
.state
= DBusXMLParser
.STATE_ANNOTATION
146 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
147 self
._cur
_object
.annotations
.append(anno
)
148 self
._cur
_object
= anno
150 self
.state
= DBusXMLParser
.STATE_IGNORED
152 # assign docs, if any
153 if 'name' in attrs
and self
.doc_comment_last_symbol
== attrs
['name']:
154 self
._cur
_object
.doc_string
= self
.doc_comment_body
155 if 'short_description' in self
.doc_comment_params
:
156 short_description
= self
.doc_comment_params
['short_description']
157 self
._cur
_object
.doc_string_brief
= short_description
158 if 'since' in self
.doc_comment_params
:
159 self
._cur
_object
.since
= \
160 self
.doc_comment_params
['since'].strip()
162 elif self
.state
== DBusXMLParser
.STATE_INTERFACE
:
163 if name
== DBusXMLParser
.STATE_METHOD
:
164 self
.state
= DBusXMLParser
.STATE_METHOD
165 method
= dbustypes
.Method(attrs
['name'])
166 self
._cur
_object
.methods
.append(method
)
167 self
._cur
_object
= method
168 elif name
== DBusXMLParser
.STATE_SIGNAL
:
169 self
.state
= DBusXMLParser
.STATE_SIGNAL
170 signal
= dbustypes
.Signal(attrs
['name'])
171 self
._cur
_object
.signals
.append(signal
)
172 self
._cur
_object
= signal
173 elif name
== DBusXMLParser
.STATE_PROPERTY
:
174 self
.state
= DBusXMLParser
.STATE_PROPERTY
175 prop
= dbustypes
.Property(attrs
['name'], attrs
['type'], attrs
['access'])
176 self
._cur
_object
.properties
.append(prop
)
177 self
._cur
_object
= prop
178 elif name
== DBusXMLParser
.STATE_ANNOTATION
:
179 self
.state
= DBusXMLParser
.STATE_ANNOTATION
180 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
181 self
._cur
_object
.annotations
.append(anno
)
182 self
._cur
_object
= anno
184 self
.state
= DBusXMLParser
.STATE_IGNORED
186 # assign docs, if any
187 if 'name' in attrs
and self
.doc_comment_last_symbol
== attrs
['name']:
188 self
._cur
_object
.doc_string
= self
.doc_comment_body
189 if 'since' in self
.doc_comment_params
:
190 self
._cur
_object
.since
= \
191 self
.doc_comment_params
['since'].strip()
193 elif self
.state
== DBusXMLParser
.STATE_METHOD
:
194 if name
== DBusXMLParser
.STATE_ARG
:
195 self
.state
= DBusXMLParser
.STATE_ARG
198 arg_name
= attrs
['name']
199 arg
= dbustypes
.Arg(arg_name
, attrs
['type'])
200 direction
= attrs
.get('direction', 'in')
201 if direction
== 'in':
202 self
._cur
_object
.in_args
.append(arg
)
203 elif direction
== 'out':
204 self
._cur
_object
.out_args
.append(arg
)
206 raise RuntimeError('Invalid direction "%s"'%(direction))
207 self
._cur
_object
= arg
208 elif name
== DBusXMLParser
.STATE_ANNOTATION
:
209 self
.state
= DBusXMLParser
.STATE_ANNOTATION
210 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
211 self
._cur
_object
.annotations
.append(anno
)
212 self
._cur
_object
= anno
214 self
.state
= DBusXMLParser
.STATE_IGNORED
216 # assign docs, if any
217 if self
.doc_comment_last_symbol
== old_cur_object
.name
:
218 if 'name' in attrs
and attrs
['name'] in self
.doc_comment_params
:
219 doc_string
= self
.doc_comment_params
[attrs
['name']]
220 if doc_string
!= None:
221 self
._cur
_object
.doc_string
= doc_string
222 if 'since' in self
.doc_comment_params
:
223 self
._cur
_object
.since
= \
224 self
.doc_comment_params
['since'].strip()
226 elif self
.state
== DBusXMLParser
.STATE_SIGNAL
:
227 if name
== DBusXMLParser
.STATE_ARG
:
228 self
.state
= DBusXMLParser
.STATE_ARG
231 arg_name
= attrs
['name']
232 arg
= dbustypes
.Arg(arg_name
, attrs
['type'])
233 self
._cur
_object
.args
.append(arg
)
234 self
._cur
_object
= arg
235 elif name
== DBusXMLParser
.STATE_ANNOTATION
:
236 self
.state
= DBusXMLParser
.STATE_ANNOTATION
237 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
238 self
._cur
_object
.annotations
.append(anno
)
239 self
._cur
_object
= anno
241 self
.state
= DBusXMLParser
.STATE_IGNORED
243 # assign docs, if any
244 if self
.doc_comment_last_symbol
== old_cur_object
.name
:
245 if 'name' in attrs
and attrs
['name'] in self
.doc_comment_params
:
246 doc_string
= self
.doc_comment_params
[attrs
['name']]
247 if doc_string
!= None:
248 self
._cur
_object
.doc_string
= doc_string
249 if 'since' in self
.doc_comment_params
:
250 self
._cur
_object
.since
= \
251 self
.doc_comment_params
['since'].strip()
253 elif self
.state
== DBusXMLParser
.STATE_PROPERTY
:
254 if name
== DBusXMLParser
.STATE_ANNOTATION
:
255 self
.state
= DBusXMLParser
.STATE_ANNOTATION
256 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
257 self
._cur
_object
.annotations
.append(anno
)
258 self
._cur
_object
= anno
260 self
.state
= DBusXMLParser
.STATE_IGNORED
262 elif self
.state
== DBusXMLParser
.STATE_ARG
:
263 if name
== DBusXMLParser
.STATE_ANNOTATION
:
264 self
.state
= DBusXMLParser
.STATE_ANNOTATION
265 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
266 self
._cur
_object
.annotations
.append(anno
)
267 self
._cur
_object
= anno
269 self
.state
= DBusXMLParser
.STATE_IGNORED
271 elif self
.state
== DBusXMLParser
.STATE_ANNOTATION
:
272 if name
== DBusXMLParser
.STATE_ANNOTATION
:
273 self
.state
= DBusXMLParser
.STATE_ANNOTATION
274 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
275 self
._cur
_object
.annotations
.append(anno
)
276 self
._cur
_object
= anno
278 self
.state
= DBusXMLParser
.STATE_IGNORED
281 raise RuntimeError('Unhandled state "%s" while entering element with name "%s"'%(self
.state
, name
))
283 self
.state_stack
.append(old_state
)
284 self
._cur
_object
_stack
.append(old_cur_object
)
286 def handle_end_element(self
, name
):
287 self
.state
= self
.state_stack
.pop()
288 self
._cur
_object
= self
._cur
_object
_stack
.pop()
290 def parse_dbus_xml(xml_data
):
291 parser
= DBusXMLParser(xml_data
)
292 return parser
.parsed_interfaces