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.1 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
26 from .utils
import print_error
31 STATE_INTERFACE
= 'interface'
32 STATE_METHOD
= 'method'
33 STATE_SIGNAL
= 'signal'
34 STATE_PROPERTY
= 'property'
36 STATE_ANNOTATION
= 'annotation'
37 STATE_IGNORED
= 'ignored'
39 def __init__(self
, xml_data
):
40 self
._parser
= xml
.parsers
.expat
.ParserCreate()
41 self
._parser
.CommentHandler
= self
.handle_comment
42 self
._parser
.CharacterDataHandler
= self
.handle_char_data
43 self
._parser
.StartElementHandler
= self
.handle_start_element
44 self
._parser
.EndElementHandler
= self
.handle_end_element
46 self
.parsed_interfaces
= []
47 self
._cur
_object
= None
49 self
.state
= DBusXMLParser
.STATE_TOP
51 self
._cur
_object
= None
52 self
._cur
_object
_stack
= []
54 self
.doc_comment_last_symbol
= ''
56 self
._parser
.Parse(xml_data
)
58 COMMENT_STATE_BEGIN
= 'begin'
59 COMMENT_STATE_PARAMS
= 'params'
60 COMMENT_STATE_BODY
= 'body'
61 COMMENT_STATE_SKIP
= 'skip'
62 def handle_comment(self
, data
):
63 comment_state
= DBusXMLParser
.COMMENT_STATE_BEGIN
;
64 lines
= data
.split('\n')
72 if comment_state
== DBusXMLParser
.COMMENT_STATE_BEGIN
:
74 colon_index
= line
.find(': ')
76 if line
.endswith(':'):
77 symbol
= line
[0:len(line
)-1]
78 comment_state
= DBusXMLParser
.COMMENT_STATE_PARAMS
80 comment_state
= DBusXMLParser
.COMMENT_STATE_SKIP
82 symbol
= line
[0:colon_index
]
83 rest_of_line
= line
[colon_index
+2:].strip()
84 if len(rest_of_line
) > 0:
85 body
+= '<para>' + rest_of_line
+ '</para>'
86 comment_state
= DBusXMLParser
.COMMENT_STATE_PARAMS
87 elif comment_state
== DBusXMLParser
.COMMENT_STATE_PARAMS
:
88 if line
.startswith('@'):
89 colon_index
= line
.find(': ')
91 comment_state
= DBusXMLParser
.COMMENT_STATE_BODY
95 body
+= orig_line
+ '\n'
97 param
= line
[1:colon_index
]
98 docs
= line
[colon_index
+ 2:]
101 comment_state
= DBusXMLParser
.COMMENT_STATE_BODY
106 body
+= orig_line
+ '\n'
107 elif comment_state
== DBusXMLParser
.COMMENT_STATE_BODY
:
112 body
+= orig_line
+ '\n'
121 self
.doc_comment_last_symbol
= symbol
122 self
.doc_comment_params
= params
123 self
.doc_comment_body
= body
125 def handle_char_data(self
, data
):
126 #print 'char_data=%s'%data
129 def handle_start_element(self
, name
, attrs
):
130 old_state
= self
.state
131 old_cur_object
= self
._cur
_object
132 if self
.state
== DBusXMLParser
.STATE_IGNORED
:
133 self
.state
= DBusXMLParser
.STATE_IGNORED
134 elif self
.state
== DBusXMLParser
.STATE_TOP
:
135 if name
== DBusXMLParser
.STATE_NODE
:
136 self
.state
= DBusXMLParser
.STATE_NODE
138 self
.state
= DBusXMLParser
.STATE_IGNORED
139 elif self
.state
== DBusXMLParser
.STATE_NODE
:
140 if name
== DBusXMLParser
.STATE_INTERFACE
:
141 self
.state
= DBusXMLParser
.STATE_INTERFACE
142 iface
= dbustypes
.Interface(attrs
['name'])
143 self
._cur
_object
= iface
144 self
.parsed_interfaces
.append(iface
)
145 elif name
== DBusXMLParser
.STATE_ANNOTATION
:
146 self
.state
= DBusXMLParser
.STATE_ANNOTATION
147 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
148 self
._cur
_object
.annotations
.append(anno
)
149 self
._cur
_object
= anno
151 self
.state
= DBusXMLParser
.STATE_IGNORED
153 # assign docs, if any
154 if 'name' in attrs
and self
.doc_comment_last_symbol
== attrs
['name']:
155 self
._cur
_object
.doc_string
= self
.doc_comment_body
156 if 'short_description' in self
.doc_comment_params
:
157 short_description
= self
.doc_comment_params
['short_description']
158 self
._cur
_object
.doc_string_brief
= short_description
159 if 'since' in self
.doc_comment_params
:
160 self
._cur
_object
.since
= \
161 self
.doc_comment_params
['since'].strip()
163 elif self
.state
== DBusXMLParser
.STATE_INTERFACE
:
164 if name
== DBusXMLParser
.STATE_METHOD
:
165 self
.state
= DBusXMLParser
.STATE_METHOD
166 method
= dbustypes
.Method(attrs
['name'])
167 self
._cur
_object
.methods
.append(method
)
168 self
._cur
_object
= method
169 elif name
== DBusXMLParser
.STATE_SIGNAL
:
170 self
.state
= DBusXMLParser
.STATE_SIGNAL
171 signal
= dbustypes
.Signal(attrs
['name'])
172 self
._cur
_object
.signals
.append(signal
)
173 self
._cur
_object
= signal
174 elif name
== DBusXMLParser
.STATE_PROPERTY
:
175 self
.state
= DBusXMLParser
.STATE_PROPERTY
176 prop
= dbustypes
.Property(attrs
['name'], attrs
['type'], attrs
['access'])
177 self
._cur
_object
.properties
.append(prop
)
178 self
._cur
_object
= prop
179 elif name
== DBusXMLParser
.STATE_ANNOTATION
:
180 self
.state
= DBusXMLParser
.STATE_ANNOTATION
181 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
182 self
._cur
_object
.annotations
.append(anno
)
183 self
._cur
_object
= anno
185 self
.state
= DBusXMLParser
.STATE_IGNORED
187 # assign docs, if any
188 if 'name' in attrs
and self
.doc_comment_last_symbol
== attrs
['name']:
189 self
._cur
_object
.doc_string
= self
.doc_comment_body
190 if 'since' in self
.doc_comment_params
:
191 self
._cur
_object
.since
= \
192 self
.doc_comment_params
['since'].strip()
194 elif self
.state
== DBusXMLParser
.STATE_METHOD
:
195 if name
== DBusXMLParser
.STATE_ARG
:
196 self
.state
= DBusXMLParser
.STATE_ARG
199 arg_name
= attrs
['name']
200 arg
= dbustypes
.Arg(arg_name
, attrs
['type'])
201 direction
= attrs
.get('direction', 'in')
202 if direction
== 'in':
203 self
._cur
_object
.in_args
.append(arg
)
204 elif direction
== 'out':
205 self
._cur
_object
.out_args
.append(arg
)
207 print_error('Invalid direction "{}"'.format(direction
))
208 self
._cur
_object
= arg
209 elif name
== DBusXMLParser
.STATE_ANNOTATION
:
210 self
.state
= DBusXMLParser
.STATE_ANNOTATION
211 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
212 self
._cur
_object
.annotations
.append(anno
)
213 self
._cur
_object
= anno
215 self
.state
= DBusXMLParser
.STATE_IGNORED
217 # assign docs, if any
218 if self
.doc_comment_last_symbol
== old_cur_object
.name
:
219 if 'name' in attrs
and attrs
['name'] in self
.doc_comment_params
:
220 doc_string
= self
.doc_comment_params
[attrs
['name']]
221 if doc_string
!= None:
222 self
._cur
_object
.doc_string
= doc_string
223 if 'since' in self
.doc_comment_params
:
224 self
._cur
_object
.since
= \
225 self
.doc_comment_params
['since'].strip()
227 elif self
.state
== DBusXMLParser
.STATE_SIGNAL
:
228 if name
== DBusXMLParser
.STATE_ARG
:
229 self
.state
= DBusXMLParser
.STATE_ARG
232 arg_name
= attrs
['name']
233 arg
= dbustypes
.Arg(arg_name
, attrs
['type'])
234 self
._cur
_object
.args
.append(arg
)
235 self
._cur
_object
= arg
236 elif name
== DBusXMLParser
.STATE_ANNOTATION
:
237 self
.state
= DBusXMLParser
.STATE_ANNOTATION
238 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
239 self
._cur
_object
.annotations
.append(anno
)
240 self
._cur
_object
= anno
242 self
.state
= DBusXMLParser
.STATE_IGNORED
244 # assign docs, if any
245 if self
.doc_comment_last_symbol
== old_cur_object
.name
:
246 if 'name' in attrs
and attrs
['name'] in self
.doc_comment_params
:
247 doc_string
= self
.doc_comment_params
[attrs
['name']]
248 if doc_string
!= None:
249 self
._cur
_object
.doc_string
= doc_string
250 if 'since' in self
.doc_comment_params
:
251 self
._cur
_object
.since
= \
252 self
.doc_comment_params
['since'].strip()
254 elif self
.state
== DBusXMLParser
.STATE_PROPERTY
:
255 if name
== DBusXMLParser
.STATE_ANNOTATION
:
256 self
.state
= DBusXMLParser
.STATE_ANNOTATION
257 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
258 self
._cur
_object
.annotations
.append(anno
)
259 self
._cur
_object
= anno
261 self
.state
= DBusXMLParser
.STATE_IGNORED
263 elif self
.state
== DBusXMLParser
.STATE_ARG
:
264 if name
== DBusXMLParser
.STATE_ANNOTATION
:
265 self
.state
= DBusXMLParser
.STATE_ANNOTATION
266 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
267 self
._cur
_object
.annotations
.append(anno
)
268 self
._cur
_object
= anno
270 self
.state
= DBusXMLParser
.STATE_IGNORED
272 elif self
.state
== DBusXMLParser
.STATE_ANNOTATION
:
273 if name
== DBusXMLParser
.STATE_ANNOTATION
:
274 self
.state
= DBusXMLParser
.STATE_ANNOTATION
275 anno
= dbustypes
.Annotation(attrs
['name'], attrs
['value'])
276 self
._cur
_object
.annotations
.append(anno
)
277 self
._cur
_object
= anno
279 self
.state
= DBusXMLParser
.STATE_IGNORED
282 print_error('Unhandled state "{}" while entering element with name "{}"'.format(self
.state
, name
))
284 self
.state_stack
.append(old_state
)
285 self
._cur
_object
_stack
.append(old_cur_object
)
287 def handle_end_element(self
, name
):
288 self
.state
= self
.state_stack
.pop()
289 self
._cur
_object
= self
._cur
_object
_stack
.pop()
291 def parse_dbus_xml(xml_data
):
292 parser
= DBusXMLParser(xml_data
)
293 return parser
.parsed_interfaces