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 from .utils import print_error
26 # See: variant_type_string_scan_internal()
27 def variant_type_string_scan(signature: str, depth_limit: int, i=0):
28 beg_char = signature[i]
31 while signature[i] != ")":
34 f'Bad signature "{signature}". Too much recursion beginning at {i}.'
36 i = variant_type_string_scan(signature, depth_limit - 1, i)
41 f'Bad signature "{signature}". Too much recursion beginning at {i}.'
43 elif signature[i] not in "bynqihuxtdsog?":
45 f'Bad signature "{signature}". "{signature[i]}" is not a valid type for dictionary keys at position {i}.'
48 i = variant_type_string_scan(signature, depth_limit - 1, i)
49 if signature[i] != "}":
51 f'Bad signature "{signature}". Dict must end with "}}" at position {i}.'
57 f'Bad signature "{signature}". Too much recursion beginning at {i}.'
59 i = variant_type_string_scan(signature, depth_limit - 1, i)
60 elif beg_char not in "bynqiuxtdsogvr*?h":
62 f'Bad signature "{signature}". Unexpected value "{beg_char}" at position {i}.'
67 # variant_check_signature() does not perform a strict validation check and
68 # should not be used in security sensitive contexts.
69 def variant_check_signature(signature: str):
70 # See: gvariant-internal.h
71 G_VARIANT_MAX_RECURSION_DEPTH = 128
72 if len(signature) > 255:
73 print_error("D-Bus maximum signature length of 255 exceeded.")
75 if s not in "ybnqiuxthdvasog(){}*":
77 f'Bad signature "{signature}". "{s}" is not a valid D-Bus type.'
80 variant_type_string_scan(signature, G_VARIANT_MAX_RECURSION_DEPTH)
83 f'Bad signature "{signature}". Error parsing string or brackets not closed.'
85 except ValueError as e:
86 print_error(e.args[0])
90 def __init__(self, key, value):
96 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, container):
98 overridden_key = utils.lookup_annotation(
99 self.annotations, "org.gtk.GDBus.C.Name"
101 if utils.is_ugly_case(overridden_key):
102 self.key_lower = overridden_key.lower()
107 utils.camel_case_to_uscore(key)
113 if len(self.since) == 0:
114 self.since = utils.lookup_since(self.annotations)
115 if len(self.since) == 0:
116 self.since = container.since
118 for a in self.annotations:
119 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
123 def __init__(self, name, signature):
125 self.signature = signature
126 self.annotations = []
130 def post_process(self, interface_prefix, cns, cns_upper, cns_lower, arg_number):
131 if len(self.doc_string) == 0:
132 self.doc_string = utils.lookup_docs(self.annotations)
133 if len(self.since) == 0:
134 self.since = utils.lookup_since(self.annotations)
136 if self.name is None:
137 self.name = "unnamed_arg%d" % arg_number
138 # default to GVariant
139 self.ctype_in_g = "GVariant *"
140 self.ctype_in = "GVariant *"
141 self.ctype_in_dup = "GVariant *"
142 self.ctype_in_default_value = "NULL"
143 self.ctype_out = "GVariant **"
144 self.gtype = "G_TYPE_VARIANT"
145 self.free_func = "g_variant_unref"
146 self.format_in = "@" + self.signature
147 self.format_out = "@" + self.signature
148 self.gvariant_get = "XXX"
149 self.gvalue_type = "variant"
150 self.gvalue_get = "g_marshal_value_peek_variant"
151 self.gvalue_set = "g_value_take_variant"
152 self.gclosure_marshaller = "g_cclosure_marshal_VOID__VARIANT"
153 self.array_annotation = ""
154 variant_check_signature(self.signature)
156 if not utils.lookup_annotation(
157 self.annotations, "org.gtk.GDBus.C.ForceGVariant"
159 if self.signature == "b":
160 self.ctype_in_g = "gboolean "
161 self.ctype_in = "gboolean "
162 self.ctype_in_default_value = "FALSE"
163 self.ctype_out = "gboolean *"
164 self.gtype = "G_TYPE_BOOLEAN"
165 self.free_func = None
167 self.format_out = "b"
168 self.gvariant_get = "g_variant_get_boolean"
169 self.gvalue_type = "boolean"
170 self.gvalue_get = "g_marshal_value_peek_boolean"
171 self.gvalue_set = "g_value_set_boolean"
172 self.gclosure_marshaller = "g_cclosure_marshal_VOID__BOOLEAN"
173 elif self.signature == "y":
174 self.ctype_in_g = "guchar "
175 self.ctype_in = "guchar "
176 self.ctype_in_default_value = "'\\0'"
177 self.ctype_out = "guchar *"
178 self.gtype = "G_TYPE_UCHAR"
179 self.free_func = None
181 self.format_out = "y"
182 self.gvariant_get = "g_variant_get_byte"
183 self.gvalue_type = "uchar"
184 self.gvalue_get = "g_marshal_value_peek_uchar"
185 self.gvalue_set = "g_value_set_uchar"
186 self.gclosure_marshaller = "g_cclosure_marshal_VOID__UCHAR"
187 elif self.signature == "n":
188 self.ctype_in_g = "gint "
189 self.ctype_in = "gint16 "
190 self.ctype_in_default_value = "0"
191 self.ctype_out = "gint16 *"
192 self.gtype = "G_TYPE_INT"
193 self.free_func = None
195 self.format_out = "n"
196 self.gvariant_get = "g_variant_get_int16"
197 self.gvalue_type = "int"
198 self.gvalue_get = "g_marshal_value_peek_int"
199 self.gvalue_set = "g_value_set_int"
200 self.gclosure_marshaller = "g_cclosure_marshal_VOID__INT"
201 elif self.signature == "q":
202 self.ctype_in_g = "guint "
203 self.ctype_in = "guint16 "
204 self.ctype_in_default_value = "0"
205 self.ctype_out = "guint16 *"
206 self.gtype = "G_TYPE_UINT"
207 self.free_func = None
209 self.format_out = "q"
210 self.gvariant_get = "g_variant_get_uint16"
211 self.gvalue_type = "uint"
212 self.gvalue_get = "g_marshal_value_peek_uint"
213 self.gvalue_set = "g_value_set_uint"
214 self.gclosure_marshaller = "g_cclosure_marshal_VOID__UINT"
215 elif self.signature == "i":
216 self.ctype_in_g = "gint "
217 self.ctype_in = "gint "
218 self.ctype_in_default_value = "0"
219 self.ctype_out = "gint *"
220 self.gtype = "G_TYPE_INT"
221 self.free_func = None
223 self.format_out = "i"
224 self.gvariant_get = "g_variant_get_int32"
225 self.gvalue_type = "int"
226 self.gvalue_get = "g_marshal_value_peek_int"
227 self.gvalue_set = "g_value_set_int"
228 self.gclosure_marshaller = "g_cclosure_marshal_VOID__INT"
229 elif self.signature == "u":
230 self.ctype_in_g = "guint "
231 self.ctype_in = "guint "
232 self.ctype_in_default_value = "0"
233 self.ctype_out = "guint *"
234 self.gtype = "G_TYPE_UINT"
235 self.free_func = None
237 self.format_out = "u"
238 self.gvariant_get = "g_variant_get_uint32"
239 self.gvalue_type = "uint"
240 self.gvalue_get = "g_marshal_value_peek_uint"
241 self.gvalue_set = "g_value_set_uint"
242 self.gclosure_marshaller = "g_cclosure_marshal_VOID__UINT"
243 elif self.signature == "x":
244 self.ctype_in_g = "gint64 "
245 self.ctype_in = "gint64 "
246 self.ctype_in_default_value = "0"
247 self.ctype_out = "gint64 *"
248 self.gtype = "G_TYPE_INT64"
249 self.free_func = None
251 self.format_out = "x"
252 self.gvariant_get = "g_variant_get_int64"
253 self.gvalue_type = "int64"
254 self.gvalue_get = "g_marshal_value_peek_int64"
255 self.gvalue_set = "g_value_set_int64"
256 self.gclosure_marshaller = None
257 elif self.signature == "t":
258 self.ctype_in_g = "guint64 "
259 self.ctype_in = "guint64 "
260 self.ctype_out = "guint64 *"
261 self.ctype_in_default_value = "0"
262 self.gtype = "G_TYPE_UINT64"
263 self.free_func = None
265 self.format_out = "t"
266 self.gvariant_get = "g_variant_get_uint64"
267 self.gvalue_type = "uint64"
268 self.gvalue_get = "g_marshal_value_peek_uint64"
269 self.gvalue_set = "g_value_set_uint64"
270 self.gclosure_marshaller = None
271 elif self.signature == "d":
272 self.ctype_in_g = "gdouble "
273 self.ctype_in = "gdouble "
274 self.ctype_in_default_value = "0.0"
275 self.ctype_out = "gdouble *"
276 self.gtype = "G_TYPE_DOUBLE"
277 self.free_func = None
279 self.format_out = "d"
280 self.gvariant_get = "g_variant_get_double"
281 self.gvalue_type = "double"
282 self.gvalue_get = "g_marshal_value_peek_double"
283 self.gvalue_set = "g_value_set_double"
284 self.gclosure_marshaller = "g_cclosure_marshal_VOID__DOUBLE"
285 elif self.signature == "s":
286 self.ctype_in_g = "const gchar *"
287 self.ctype_in = "const gchar *"
288 self.ctype_in_dup = "gchar *"
289 self.ctype_in_default_value = "NULL"
290 self.ctype_out = "gchar **"
291 self.gtype = "G_TYPE_STRING"
292 self.free_func = "g_free"
294 self.format_out = "s"
295 self.gvariant_get = "g_variant_get_string"
296 self.gvalue_type = "string"
297 self.gvalue_get = "g_marshal_value_peek_string"
298 self.gvalue_set = "g_value_set_string"
299 self.gclosure_marshaller = "g_cclosure_marshal_VOID__STRING"
300 elif self.signature == "o":
301 self.ctype_in_g = "const gchar *"
302 self.ctype_in = "const gchar *"
303 self.ctype_in_dup = "gchar *"
304 self.ctype_in_default_value = "NULL"
305 self.ctype_out = "gchar **"
306 self.gtype = "G_TYPE_STRING"
307 self.free_func = "g_free"
309 self.format_out = "o"
310 self.gvariant_get = "g_variant_get_string"
311 self.gvalue_type = "string"
312 self.gvalue_get = "g_marshal_value_peek_string"
313 self.gvalue_set = "g_value_set_string"
314 self.gclosure_marshaller = "g_cclosure_marshal_VOID__STRING"
315 elif self.signature == "g":
316 self.ctype_in_g = "const gchar *"
317 self.ctype_in = "const gchar *"
318 self.ctype_in_dup = "gchar *"
319 self.ctype_in_default_value = "NULL"
320 self.ctype_out = "gchar **"
321 self.gtype = "G_TYPE_STRING"
322 self.free_func = "g_free"
324 self.format_out = "g"
325 self.gvariant_get = "g_variant_get_string"
326 self.gvalue_type = "string"
327 self.gvalue_get = "g_marshal_value_peek_string"
328 self.gvalue_set = "g_value_set_string"
329 self.gclosure_marshaller = "g_cclosure_marshal_VOID__STRING"
330 elif self.signature == "ay":
331 self.ctype_in_g = "const gchar *"
332 self.ctype_in = "const gchar *"
333 self.ctype_in_default_value = "NULL"
334 self.ctype_in_dup = "gchar *"
335 self.ctype_out = "gchar **"
336 self.gtype = "G_TYPE_STRING"
337 self.free_func = "g_free"
338 self.format_in = "^ay"
339 self.format_out = "^ay"
340 self.gvariant_get = "g_variant_get_bytestring"
341 self.gvalue_type = "string"
342 self.gvalue_get = "g_marshal_value_peek_string"
343 self.gvalue_set = "g_value_set_string"
344 self.gclosure_marshaller = "g_cclosure_marshal_VOID__STRING"
345 elif self.signature == "as":
346 self.ctype_in_g = "const gchar *const *"
347 self.ctype_in = "const gchar *const *"
348 self.ctype_in_dup = "gchar **"
349 self.ctype_in_default_value = "NULL"
350 self.ctype_out = "gchar ***"
351 self.gtype = "G_TYPE_STRV"
352 self.free_func = "g_strfreev"
353 self.format_in = "^as"
354 self.format_out = "^as"
355 self.gvariant_get = "g_variant_get_strv"
356 self.gvalue_type = "boxed"
357 self.gvalue_get = "g_marshal_value_peek_boxed"
358 self.gvalue_set = "g_value_take_boxed"
359 self.gclosure_marshaller = "g_cclosure_marshal_VOID__BOXED"
360 self.array_annotation = "(array zero-terminated=1)"
361 elif self.signature == "ao":
362 self.ctype_in_g = "const gchar *const *"
363 self.ctype_in = "const gchar *const *"
364 self.ctype_in_dup = "gchar **"
365 self.ctype_in_default_value = "NULL"
366 self.ctype_out = "gchar ***"
367 self.gtype = "G_TYPE_STRV"
368 self.free_func = "g_strfreev"
369 self.format_in = "^ao"
370 self.format_out = "^ao"
371 self.gvariant_get = "g_variant_get_objv"
372 self.gvalue_type = "boxed"
373 self.gvalue_get = "g_marshal_value_peek_boxed"
374 self.gvalue_set = "g_value_take_boxed"
375 self.gclosure_marshaller = "g_cclosure_marshal_VOID__BOXED"
376 self.array_annotation = "(array zero-terminated=1)"
377 elif self.signature == "aay":
378 self.ctype_in_g = "const gchar *const *"
379 self.ctype_in = "const gchar *const *"
380 self.ctype_in_dup = "gchar **"
381 self.ctype_in_default_value = "NULL"
382 self.ctype_out = "gchar ***"
383 self.gtype = "G_TYPE_STRV"
384 self.free_func = "g_strfreev"
385 self.format_in = "^aay"
386 self.format_out = "^aay"
387 self.gvariant_get = "g_variant_get_bytestring_array"
388 self.gvalue_type = "boxed"
389 self.gvalue_get = "g_marshal_value_peek_boxed"
390 self.gvalue_set = "g_value_take_boxed"
391 self.gclosure_marshaller = "g_cclosure_marshal_VOID__BOXED"
392 self.array_annotation = "(array zero-terminated=1)"
394 for a in self.annotations:
395 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
399 def __init__(self, name, h_type_implies_unix_fd=True):
401 self.h_type_implies_unix_fd = h_type_implies_unix_fd
404 self.annotations = []
407 self.deprecated = False
411 self, interface_prefix, cns, cns_upper, cns_lower, containing_iface
413 if len(self.doc_string) == 0:
414 self.doc_string = utils.lookup_docs(self.annotations)
415 if len(self.since) == 0:
416 self.since = utils.lookup_since(self.annotations)
417 if len(self.since) == 0:
418 self.since = containing_iface.since
421 overridden_name = utils.lookup_annotation(
422 self.annotations, "org.gtk.GDBus.C.Name"
424 if utils.is_ugly_case(overridden_name):
425 self.name_lower = overridden_name.lower()
428 name = overridden_name
429 self.name_lower = utils.camel_case_to_uscore(name).lower().replace("-", "_")
430 self.name_hyphen = self.name_lower.replace("_", "-")
433 for a in self.in_args:
434 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count)
436 if self.h_type_implies_unix_fd and "h" in a.signature:
439 for a in self.out_args:
440 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count)
442 if self.h_type_implies_unix_fd and "h" in a.signature:
446 utils.lookup_annotation(self.annotations, "org.freedesktop.DBus.Deprecated")
449 self.deprecated = True
451 if utils.lookup_annotation(self.annotations, "org.gtk.GDBus.C.UnixFD"):
454 self.marshaller_ret_arg = Arg("return", "b")
455 self.marshaller_ret_arg.post_process(None, None, None, None, None)
457 method_invocation_arg = Arg("method_invocation", None)
458 method_invocation_arg.ctype_in = "GDBusMethodInvocation *"
459 method_invocation_arg.gvalue_type = "object"
460 method_invocation_arg.gvalue_get = "g_marshal_value_peek_object"
461 method_invocation_arg.gclosure_marshaller = None
462 self.marshaller_in_args = [method_invocation_arg] + self.in_args
465 fd_list_arg = Arg("fd_list", None)
466 fd_list_arg.ctype_in = "GUnixFDList *"
467 fd_list_arg.gvalue_type = "object"
468 fd_list_arg.gvalue_get = "g_marshal_value_peek_object"
469 fd_list_arg.gclosure_marshaller = None
470 self.marshaller_in_args.insert(0, fd_list_arg)
472 for a in self.annotations:
473 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
477 def __init__(self, name):
480 self.annotations = []
483 self.deprecated = False
486 self, interface_prefix, cns, cns_upper, cns_lower, containing_iface
488 if len(self.doc_string) == 0:
489 self.doc_string = utils.lookup_docs(self.annotations)
490 if len(self.since) == 0:
491 self.since = utils.lookup_since(self.annotations)
492 if len(self.since) == 0:
493 self.since = containing_iface.since
496 overridden_name = utils.lookup_annotation(
497 self.annotations, "org.gtk.GDBus.C.Name"
499 if utils.is_ugly_case(overridden_name):
500 self.name_lower = overridden_name.lower()
503 name = overridden_name
504 self.name_lower = utils.camel_case_to_uscore(name).lower().replace("-", "_")
505 self.name_upper = self.name_lower.upper()
506 self.name_hyphen = self.name_lower.replace("_", "-")
507 self.upper_id_name = "_".join(
508 [cns_upper, containing_iface.name_upper, self.name_upper]
513 a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count)
517 utils.lookup_annotation(self.annotations, "org.freedesktop.DBus.Deprecated")
520 self.deprecated = True
522 self.marshaller_ret_arg = None
523 self.marshaller_in_args = self.args
525 for a in self.annotations:
526 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
530 def __init__(self, name, signature, access):
532 self.signature = signature
534 self.annotations = []
535 self.arg = Arg("value", self.signature)
536 self.arg.annotations = self.annotations
537 self.readable = False
538 self.writable = False
539 if self.access == "readwrite":
542 elif self.access == "read":
544 elif self.access == "write":
547 print_error('Invalid access type "{}"'.format(self.access))
550 self.deprecated = False
551 self.emits_changed_signal = True
554 self, interface_prefix, cns, cns_upper, cns_lower, containing_iface
556 if len(self.doc_string) == 0:
557 self.doc_string = utils.lookup_docs(self.annotations)
558 if len(self.since) == 0:
559 self.since = utils.lookup_since(self.annotations)
560 if len(self.since) == 0:
561 self.since = containing_iface.since
564 overridden_name = utils.lookup_annotation(
565 self.annotations, "org.gtk.GDBus.C.Name"
567 if utils.is_ugly_case(overridden_name):
568 self.name_lower = overridden_name.lower()
571 name = overridden_name
572 self.name_lower = utils.camel_case_to_uscore(name).lower().replace("-", "_")
573 self.name_hyphen = self.name_lower.replace("_", "-")
574 # don't clash with the GType getter, e.g.:
575 # GType foo_bar_get_type (void); G_GNUC_CONST
576 if self.name_lower == "type":
577 self.name_lower = "type_"
580 self.arg.annotations = self.annotations
581 self.arg.post_process(interface_prefix, cns, cns_upper, cns_lower, 0)
584 utils.lookup_annotation(self.annotations, "org.freedesktop.DBus.Deprecated")
587 self.deprecated = True
589 for a in self.annotations:
590 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
592 # FIXME: for now we only support 'false' and 'const' on the signal itself,
594 # http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
596 if utils.lookup_annotation(
597 self.annotations, "org.freedesktop.DBus.Property.EmitsChangedSignal"
598 ) in ("false", "const"):
599 self.emits_changed_signal = False
603 def __init__(self, name):
608 self.annotations = []
610 self.doc_string_brief = ""
612 self.deprecated = False
614 def post_process(self, interface_prefix, c_namespace):
615 if len(self.doc_string) == 0:
616 self.doc_string = utils.lookup_docs(self.annotations)
617 if len(self.doc_string_brief) == 0:
618 self.doc_string_brief = utils.lookup_brief_docs(self.annotations)
619 if len(self.since) == 0:
620 self.since = utils.lookup_since(self.annotations)
622 if len(c_namespace) > 0:
623 if utils.is_ugly_case(c_namespace):
624 cns = c_namespace.replace("_", "")
625 cns_upper = c_namespace.upper() + "_"
626 cns_lower = c_namespace.lower() + "_"
629 cns_upper = utils.camel_case_to_uscore(c_namespace).upper() + "_"
630 cns_lower = utils.camel_case_to_uscore(c_namespace).lower() + "_"
636 overridden_name = utils.lookup_annotation(
637 self.annotations, "org.gtk.GDBus.C.Name"
639 if utils.is_ugly_case(overridden_name):
640 name = overridden_name.replace("_", "")
641 name_with_ns = cns + name
642 self.name_without_prefix = name
643 self.camel_name = name_with_ns
644 self.ns_upper = cns_upper
645 self.name_lower = cns_lower + overridden_name.lower()
646 self.name_upper = overridden_name.upper()
648 # print_error('handle Ugly_Case "{}"'.format(overridden_name))
651 name = overridden_name
654 if name.startswith(interface_prefix):
655 name = name[len(interface_prefix) :]
656 self.name_without_prefix = name
657 name = utils.strip_dots(name)
658 name_with_ns = utils.strip_dots(cns + "." + name)
659 self.camel_name = name_with_ns
660 self.ns_upper = cns_upper
661 self.name_lower = cns_lower + utils.camel_case_to_uscore(name)
662 self.name_upper = utils.camel_case_to_uscore(name).upper()
664 self.name_hyphen = self.name_upper.lower().replace("_", "-")
667 utils.lookup_annotation(self.annotations, "org.freedesktop.DBus.Deprecated")
670 self.deprecated = True
672 for m in self.methods:
673 m.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
675 for s in self.signals:
676 s.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
678 for p in self.properties:
679 p.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
681 for a in self.annotations:
682 a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
685 self.signals_enum_name = "_".join([cns_upper, self.name_upper, "SIGNALS"])