00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "dbus-gparser.h"
00024 #include "dbus/dbus-glib-lowlevel.h"
00025 #include "dbus-gidl.h"
00026 #include "dbus-gobject.h"
00027 #include "dbus/dbus-signature.h"
00028 #include <string.h>
00029
00030 #include <libintl.h>
00031 #define _(x) gettext ((x))
00032 #define N_(x) x
00033
00034 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00035
00036 #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
00037
00038 typedef struct
00039 {
00040 const char *name;
00041 const char **retloc;
00042 } LocateAttr;
00043
00044 static gboolean
00045 locate_attributes (const char *element_name,
00046 const char **attribute_names,
00047 const char **attribute_values,
00048 GError **error,
00049 const char *first_attribute_name,
00050 const char **first_attribute_retloc,
00051 ...)
00052 {
00053 va_list args;
00054 const char *name;
00055 const char **retloc;
00056 int n_attrs;
00057 #define MAX_ATTRS 24
00058 LocateAttr attrs[MAX_ATTRS];
00059 gboolean retval;
00060 int i;
00061
00062 g_return_val_if_fail (first_attribute_name != NULL, FALSE);
00063 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
00064
00065 retval = TRUE;
00066
00067 n_attrs = 1;
00068 attrs[0].name = first_attribute_name;
00069 attrs[0].retloc = first_attribute_retloc;
00070 *first_attribute_retloc = NULL;
00071
00072 va_start (args, first_attribute_retloc);
00073
00074 name = va_arg (args, const char*);
00075 retloc = va_arg (args, const char**);
00076
00077 while (name != NULL)
00078 {
00079 if (retloc == NULL)
00080 {
00081 va_end (args);
00082 return FALSE;
00083 }
00084
00085 g_assert (n_attrs < MAX_ATTRS);
00086
00087 attrs[n_attrs].name = name;
00088 attrs[n_attrs].retloc = retloc;
00089 n_attrs += 1;
00090 *retloc = NULL;
00091
00092 name = va_arg (args, const char*);
00093 retloc = va_arg (args, const char**);
00094 }
00095
00096 va_end (args);
00097
00098 if (!retval)
00099 return retval;
00100
00101 i = 0;
00102 while (attribute_names[i])
00103 {
00104 int j;
00105 gboolean found;
00106
00107 found = FALSE;
00108 j = 0;
00109 while (j < n_attrs)
00110 {
00111 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
00112 {
00113 retloc = attrs[j].retloc;
00114
00115 if (*retloc != NULL)
00116 {
00117 g_set_error (error,
00118 G_MARKUP_ERROR,
00119 G_MARKUP_ERROR_PARSE,
00120 _("Attribute \"%s\" repeated twice on the same <%s> element"),
00121 attrs[j].name, element_name);
00122 retval = FALSE;
00123 goto out;
00124 }
00125
00126 *retloc = attribute_values[i];
00127 found = TRUE;
00128 }
00129
00130 ++j;
00131 }
00132
00133 if (!found)
00134 {
00135 g_set_error (error,
00136 G_MARKUP_ERROR,
00137 G_MARKUP_ERROR_PARSE,
00138 _("Attribute \"%s\" is invalid on <%s> element in this context"),
00139 attribute_names[i], element_name);
00140 retval = FALSE;
00141 goto out;
00142 }
00143
00144 ++i;
00145 }
00146
00147 out:
00148 return retval;
00149 }
00150
00151 #if 0
00152 static gboolean
00153 check_no_attributes (const char *element_name,
00154 const char **attribute_names,
00155 const char **attribute_values,
00156 GError **error)
00157 {
00158 if (attribute_names[0] != NULL)
00159 {
00160 g_set_error (error,
00161 G_MARKUP_ERROR,
00162 G_MARKUP_ERROR_PARSE,
00163 _("Attribute \"%s\" is invalid on <%s> element in this context"),
00164 attribute_names[0], element_name);
00165 return FALSE;
00166 }
00167
00168 return TRUE;
00169 }
00170 #endif
00171
00172 struct Parser
00173 {
00174 int refcount;
00175
00176 NodeInfo *result;
00177 GSList *node_stack;
00178 InterfaceInfo *interface;
00179 MethodInfo *method;
00180 SignalInfo *signal;
00181 PropertyInfo *property;
00182 ArgInfo *arg;
00183 gboolean in_annotation;
00184 };
00185
00186 Parser*
00187 parser_new (void)
00188 {
00189 Parser *parser;
00190
00191 parser = g_new0 (Parser, 1);
00192
00193 parser->refcount = 1;
00194
00195 return parser;
00196 }
00197
00198 Parser *
00199 parser_ref (Parser *parser)
00200 {
00201 parser->refcount += 1;
00202
00203 return parser;
00204 }
00205
00206 void
00207 parser_unref (Parser *parser)
00208 {
00209 parser->refcount -= 1;
00210 if (parser->refcount == 0)
00211 {
00212 if (parser->result)
00213 node_info_unref (parser->result);
00214
00215 g_free (parser);
00216 }
00217 }
00218
00219 gboolean
00220 parser_check_doctype (Parser *parser,
00221 const char *doctype,
00222 GError **error)
00223 {
00224 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00225
00226 if (strcmp (doctype, "node") != 0)
00227 {
00228 g_set_error (error,
00229 G_MARKUP_ERROR,
00230 G_MARKUP_ERROR_PARSE,
00231 "D-BUS description file has the wrong document type %s, use node or interface",
00232 doctype);
00233 return FALSE;
00234 }
00235 else
00236 return TRUE;
00237 }
00238
00239 static gboolean
00240 parse_node (Parser *parser,
00241 const char *element_name,
00242 const char **attribute_names,
00243 const char **attribute_values,
00244 GError **error)
00245 {
00246 const char *name;
00247 NodeInfo *node;
00248
00249 if (parser->interface ||
00250 parser->method ||
00251 parser->signal ||
00252 parser->property ||
00253 parser->arg ||
00254 parser->in_annotation)
00255 {
00256 g_set_error (error, G_MARKUP_ERROR,
00257 G_MARKUP_ERROR_PARSE,
00258 _("Can't put <%s> element here"),
00259 element_name);
00260 return FALSE;
00261 }
00262
00263 name = NULL;
00264 if (!locate_attributes (element_name, attribute_names,
00265 attribute_values, error,
00266 "name", &name,
00267 NULL))
00268 return FALSE;
00269
00270
00271 if (parser->node_stack != NULL && name == NULL)
00272 {
00273 g_set_error (error, G_MARKUP_ERROR,
00274 G_MARKUP_ERROR_PARSE,
00275 _("\"%s\" attribute required on <%s> element "),
00276 "name", element_name);
00277 return FALSE;
00278 }
00279
00280
00281 if (parser->node_stack == NULL && name && *name != '/')
00282 {
00283 g_set_error (error, G_MARKUP_ERROR,
00284 G_MARKUP_ERROR_PARSE,
00285 _("\"%s\" attribute on <%s> element must be an absolute object path, \"%s\" not OK"),
00286 "name", element_name, name);
00287 return FALSE;
00288 }
00289
00290
00291 if (parser->node_stack != NULL && name && *name == '/')
00292 {
00293 g_set_error (error, G_MARKUP_ERROR,
00294 G_MARKUP_ERROR_PARSE,
00295 _("\"%s\" attribute on <%s> element must not be an absolute object path, \"%s\" starts with /"),
00296 "name", element_name, name);
00297 return FALSE;
00298 }
00299
00300 node = node_info_new (name);
00301
00302 if (parser->node_stack != NULL)
00303 {
00304 node_info_add_node (parser->node_stack->data,
00305 node);
00306 }
00307
00308 parser->node_stack = g_slist_prepend (parser->node_stack,
00309 node);
00310
00311 return TRUE;
00312 }
00313
00314 static gboolean
00315 parse_interface (Parser *parser,
00316 const char *element_name,
00317 const char **attribute_names,
00318 const char **attribute_values,
00319 GError **error)
00320 {
00321 const char *name;
00322 InterfaceInfo *iface;
00323 NodeInfo *top;
00324
00325 if (parser->interface ||
00326 parser->method ||
00327 parser->signal ||
00328 parser->property ||
00329 parser->arg ||
00330 parser->in_annotation ||
00331 (parser->node_stack == NULL))
00332 {
00333 g_set_error (error, G_MARKUP_ERROR,
00334 G_MARKUP_ERROR_PARSE,
00335 _("Can't put <%s> element here"),
00336 element_name);
00337 return FALSE;
00338 }
00339
00340 name = NULL;
00341 if (!locate_attributes (element_name, attribute_names,
00342 attribute_values, error,
00343 "name", &name,
00344 NULL))
00345 return FALSE;
00346
00347 if (name == NULL)
00348 {
00349 g_set_error (error, G_MARKUP_ERROR,
00350 G_MARKUP_ERROR_PARSE,
00351 _("\"%s\" attribute required on <%s> element "),
00352 "name", element_name);
00353 return FALSE;
00354 }
00355
00356 top = parser->node_stack->data;
00357
00358 iface = interface_info_new (name);
00359 node_info_add_interface (top, iface);
00360 interface_info_unref (iface);
00361
00362 parser->interface = iface;
00363
00364 return TRUE;
00365 }
00366
00367 static gboolean
00368 parse_method (Parser *parser,
00369 const char *element_name,
00370 const char **attribute_names,
00371 const char **attribute_values,
00372 GError **error)
00373 {
00374 const char *name;
00375 MethodInfo *method;
00376
00377 if (parser->interface == NULL ||
00378 parser->node_stack == NULL ||
00379 parser->method ||
00380 parser->signal ||
00381 parser->property ||
00382 parser->in_annotation ||
00383 parser->arg)
00384 {
00385 g_set_error (error, G_MARKUP_ERROR,
00386 G_MARKUP_ERROR_PARSE,
00387 _("Can't put <%s> element here"),
00388 element_name);
00389 return FALSE;
00390 }
00391
00392 name = NULL;
00393 if (!locate_attributes (element_name, attribute_names,
00394 attribute_values, error,
00395 "name", &name,
00396 NULL))
00397 return FALSE;
00398
00399 if (name == NULL)
00400 {
00401 g_set_error (error, G_MARKUP_ERROR,
00402 G_MARKUP_ERROR_PARSE,
00403 _("\"%s\" attribute required on <%s> element "),
00404 "name", element_name);
00405 return FALSE;
00406 }
00407
00408 method = method_info_new (name);
00409 interface_info_add_method (parser->interface, method);
00410 method_info_unref (method);
00411
00412 parser->method = method;
00413
00414 return TRUE;
00415 }
00416
00417 static gboolean
00418 parse_signal (Parser *parser,
00419 const char *element_name,
00420 const char **attribute_names,
00421 const char **attribute_values,
00422 GError **error)
00423 {
00424 const char *name;
00425 SignalInfo *signal;
00426
00427 if (parser->interface == NULL ||
00428 parser->node_stack == NULL ||
00429 parser->signal ||
00430 parser->method ||
00431 parser->property ||
00432 parser->in_annotation ||
00433 parser->arg)
00434 {
00435 g_set_error (error, G_MARKUP_ERROR,
00436 G_MARKUP_ERROR_PARSE,
00437 _("Can't put <%s> element here"),
00438 element_name);
00439 return FALSE;
00440 }
00441
00442 name = NULL;
00443 if (!locate_attributes (element_name, attribute_names,
00444 attribute_values, error,
00445 "name", &name,
00446 NULL))
00447 return FALSE;
00448
00449 if (name == NULL)
00450 {
00451 g_set_error (error, G_MARKUP_ERROR,
00452 G_MARKUP_ERROR_PARSE,
00453 _("\"%s\" attribute required on <%s> element "),
00454 "name", element_name);
00455 return FALSE;
00456 }
00457
00458 signal = signal_info_new (name);
00459 interface_info_add_signal (parser->interface, signal);
00460 signal_info_unref (signal);
00461
00462 parser->signal = signal;
00463
00464 return TRUE;
00465 }
00466
00467 static gboolean
00468 validate_signature (const char *str,
00469 const char *element_name,
00470 GError **error)
00471 {
00472 DBusError derror;
00473
00474 dbus_error_init (&derror);
00475
00476 if (!dbus_signature_validate (str, &derror))
00477 {
00478 dbus_set_g_error (error, &derror);
00479 return FALSE;
00480 }
00481 return TRUE;
00482 }
00483
00484 static gboolean
00485 parse_property (Parser *parser,
00486 const char *element_name,
00487 const char **attribute_names,
00488 const char **attribute_values,
00489 GError **error)
00490 {
00491 const char *name;
00492 const char *access;
00493 const char *type;
00494 PropertyInfo *property;
00495 PropertyAccessFlags access_flags;
00496
00497 if (parser->interface == NULL ||
00498 parser->node_stack == NULL ||
00499 parser->signal ||
00500 parser->method ||
00501 parser->property ||
00502 parser->in_annotation ||
00503 parser->arg)
00504 {
00505 g_set_error (error, G_MARKUP_ERROR,
00506 G_MARKUP_ERROR_PARSE,
00507 _("Can't put <%s> element here"),
00508 element_name);
00509 return FALSE;
00510 }
00511
00512 name = NULL;
00513 if (!locate_attributes (element_name, attribute_names,
00514 attribute_values, error,
00515 "name", &name,
00516 "access", &access,
00517 "type", &type,
00518 NULL))
00519 return FALSE;
00520
00521 if (name == NULL)
00522 {
00523 g_set_error (error, G_MARKUP_ERROR,
00524 G_MARKUP_ERROR_PARSE,
00525 _("\"%s\" attribute required on <%s> element "),
00526 "name", element_name);
00527 return FALSE;
00528 }
00529
00530 if (access == NULL)
00531 {
00532 g_set_error (error, G_MARKUP_ERROR,
00533 G_MARKUP_ERROR_PARSE,
00534 _("\"%s\" attribute required on <%s> element "),
00535 "access", element_name);
00536 return FALSE;
00537 }
00538
00539 if (type == NULL)
00540 {
00541 g_set_error (error, G_MARKUP_ERROR,
00542 G_MARKUP_ERROR_PARSE,
00543 _("\"%s\" attribute required on <%s> element "),
00544 "type", element_name);
00545 return FALSE;
00546 }
00547
00548 if (!validate_signature (type, element_name, error))
00549 return FALSE;
00550
00551 access_flags = 0;
00552 if (strcmp (access, "readwrite") == 0)
00553 access_flags = PROPERTY_READ | PROPERTY_WRITE;
00554 else if (strcmp (access, "read") == 0)
00555 access_flags = PROPERTY_READ;
00556 else if (strcmp (access, "write") == 0)
00557 access_flags = PROPERTY_WRITE;
00558 else
00559 {
00560 g_set_error (error, G_MARKUP_ERROR,
00561 G_MARKUP_ERROR_PARSE,
00562 _("access=\"%s\" must have value readwrite, read, or write on %s\n"),
00563 access, element_name);
00564 return FALSE;
00565 }
00566
00567 property = property_info_new (name, type, access_flags);
00568 interface_info_add_property (parser->interface, property);
00569 property_info_unref (property);
00570
00571 parser->property = property;
00572
00573 return TRUE;
00574 }
00575
00576 static gboolean
00577 parse_arg (Parser *parser,
00578 const char *element_name,
00579 const char **attribute_names,
00580 const char **attribute_values,
00581 GError **error)
00582 {
00583 const char *name;
00584 const char *type;
00585 const char *direction;
00586 ArgDirection dir;
00587 ArgInfo *arg;
00588 char *generated_name;
00589
00590 if (!(parser->method || parser->signal) ||
00591 parser->node_stack == NULL ||
00592 parser->property ||
00593 parser->in_annotation ||
00594 parser->arg)
00595 {
00596 g_set_error (error, G_MARKUP_ERROR,
00597 G_MARKUP_ERROR_PARSE,
00598 _("Can't put <%s> element here"),
00599 element_name);
00600 return FALSE;
00601 }
00602
00603 name = NULL;
00604 if (!locate_attributes (element_name, attribute_names,
00605 attribute_values, error,
00606 "name", &name,
00607 "type", &type,
00608 "direction", &direction,
00609 NULL))
00610 return FALSE;
00611
00612
00613
00614 if (type == NULL)
00615 {
00616 g_set_error (error, G_MARKUP_ERROR,
00617 G_MARKUP_ERROR_PARSE,
00618 _("\"%s\" attribute required on <%s> element "),
00619 "type", element_name);
00620 return FALSE;
00621 }
00622
00623 if (direction == NULL)
00624 {
00625
00626 if (parser->method)
00627 direction = "in";
00628 else if (parser->signal)
00629 direction = "out";
00630 else
00631 g_assert_not_reached ();
00632 }
00633
00634 dir = ARG_INVALID;
00635
00636 if (strcmp (direction, "in") == 0)
00637 dir = ARG_IN;
00638 else if (strcmp (direction, "out") == 0)
00639 dir = ARG_OUT;
00640
00641 if (dir == ARG_INVALID ||
00642 (parser->signal && dir == ARG_IN))
00643 {
00644 if (parser->signal)
00645 g_set_error (error, G_MARKUP_ERROR,
00646 G_MARKUP_ERROR_PARSE,
00647 _("Signals must have direction=\"out\" (just omit the direction attribute)"));
00648 else
00649 g_set_error (error, G_MARKUP_ERROR,
00650 G_MARKUP_ERROR_PARSE,
00651 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
00652 "direction", element_name);
00653 return FALSE;
00654 }
00655
00656 if (!validate_signature (type, element_name, error))
00657 return FALSE;
00658
00659 generated_name = NULL;
00660 if (name == NULL)
00661 generated_name = g_strdup_printf ("arg%d",
00662 parser->method ?
00663 method_info_get_n_args (parser->method) :
00664 signal_info_get_n_args (parser->signal));
00665
00666 arg = arg_info_new (name ? name : generated_name, dir, type);
00667 if (parser->method)
00668 method_info_add_arg (parser->method, arg);
00669 else if (parser->signal)
00670 signal_info_add_arg (parser->signal, arg);
00671 else
00672 g_assert_not_reached ();
00673
00674 g_free (generated_name);
00675
00676 arg_info_unref (arg);
00677
00678 parser->arg = arg;
00679
00680 return TRUE;
00681 }
00682
00683 static gboolean
00684 parse_annotation (Parser *parser,
00685 const char *element_name,
00686 const char **attribute_names,
00687 const char **attribute_values,
00688 GError **error)
00689 {
00690 const char *name;
00691 const char *value;
00692
00693 if (!(parser->method || parser->interface || parser->arg) ||
00694 parser->node_stack == NULL ||
00695 parser->signal ||
00696 parser->property ||
00697 parser->in_annotation)
00698 {
00699 g_set_error (error, G_MARKUP_ERROR,
00700 G_MARKUP_ERROR_PARSE,
00701 _("Can't put <%s> element here"),
00702 element_name);
00703 return FALSE;
00704 }
00705
00706 name = NULL;
00707 if (!locate_attributes (element_name, attribute_names,
00708 attribute_values, error,
00709 "name", &name,
00710 "value", &value,
00711 NULL))
00712 return FALSE;
00713
00714 if (name == NULL)
00715 {
00716 g_set_error (error, G_MARKUP_ERROR,
00717 G_MARKUP_ERROR_PARSE,
00718 _("\"%s\" attribute required on <%s> element "),
00719 "name", element_name);
00720 return FALSE;
00721 }
00722 if (value == NULL)
00723 {
00724 g_set_error (error, G_MARKUP_ERROR,
00725 G_MARKUP_ERROR_PARSE,
00726 _("\"%s\" attribute required on <%s> element "),
00727 "value", element_name);
00728 return FALSE;
00729 }
00730
00731 if (parser->arg)
00732 arg_info_add_annotation (parser->arg, name, value);
00733 else if (parser->method)
00734 method_info_add_annotation (parser->method, name, value);
00735 else if (parser->interface)
00736 interface_info_add_annotation (parser->interface, name, value);
00737 else
00738 g_assert_not_reached ();
00739
00740 parser->in_annotation = TRUE;
00741
00742 return TRUE;
00743 }
00744
00745 gboolean
00746 parser_start_element (Parser *parser,
00747 const char *element_name,
00748 const char **attribute_names,
00749 const char **attribute_values,
00750 GError **error)
00751 {
00752 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00753
00754 if (ELEMENT_IS ("node"))
00755 {
00756 if (!parse_node (parser, element_name, attribute_names,
00757 attribute_values, error))
00758 return FALSE;
00759 }
00760 else if (ELEMENT_IS ("interface"))
00761 {
00762 if (!parse_interface (parser, element_name, attribute_names,
00763 attribute_values, error))
00764 return FALSE;
00765 }
00766 else if (ELEMENT_IS ("method"))
00767 {
00768 if (!parse_method (parser, element_name, attribute_names,
00769 attribute_values, error))
00770 return FALSE;
00771 }
00772 else if (ELEMENT_IS ("signal"))
00773 {
00774 if (!parse_signal (parser, element_name, attribute_names,
00775 attribute_values, error))
00776 return FALSE;
00777 }
00778 else if (ELEMENT_IS ("property"))
00779 {
00780 if (!parse_property (parser, element_name, attribute_names,
00781 attribute_values, error))
00782 return FALSE;
00783 }
00784 else if (ELEMENT_IS ("arg"))
00785 {
00786 if (!parse_arg (parser, element_name, attribute_names,
00787 attribute_values, error))
00788 return FALSE;
00789 }
00790 else if (ELEMENT_IS ("annotation"))
00791 {
00792 if (!parse_annotation (parser, element_name, attribute_names,
00793 attribute_values, error))
00794 return FALSE;
00795 }
00796 else
00797 {
00798 g_set_error (error, G_MARKUP_ERROR,
00799 G_MARKUP_ERROR_PARSE,
00800 _("Element <%s> not recognized"),
00801 element_name);
00802 }
00803
00804 return TRUE;
00805 }
00806
00807 gboolean
00808 parser_end_element (Parser *parser,
00809 const char *element_name,
00810 GError **error)
00811 {
00812 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00813
00814 if (ELEMENT_IS ("interface"))
00815 {
00816 parser->interface = NULL;
00817 }
00818 else if (ELEMENT_IS ("method"))
00819 {
00820 parser->method = NULL;
00821 }
00822 else if (ELEMENT_IS ("signal"))
00823 {
00824 parser->signal = NULL;
00825 }
00826 else if (ELEMENT_IS ("property"))
00827 {
00828 parser->property = NULL;
00829 }
00830 else if (ELEMENT_IS ("arg"))
00831 {
00832 parser->arg = NULL;
00833 }
00834 else if (ELEMENT_IS ("annotation"))
00835 {
00836 parser->in_annotation = FALSE;
00837 }
00838 else if (ELEMENT_IS ("node"))
00839 {
00840 NodeInfo *top;
00841
00842 g_assert (parser->node_stack != NULL);
00843 top = parser->node_stack->data;
00844
00845 parser->node_stack = g_slist_remove (parser->node_stack,
00846 top);
00847
00848 if (parser->node_stack == NULL)
00849 parser->result = top;
00850 }
00851 else
00852 g_assert_not_reached ();
00853
00854 return TRUE;
00855 }
00856
00857 gboolean
00858 parser_content (Parser *parser,
00859 const char *content,
00860 int len,
00861 GError **error)
00862 {
00863 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00864
00865
00866
00867 return TRUE;
00868 }
00869
00870 gboolean
00871 parser_finished (Parser *parser,
00872 GError **error)
00873 {
00874 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00875
00876 return TRUE;
00877 }
00878
00879 NodeInfo*
00880 parser_get_nodes (Parser *parser)
00881 {
00882 return parser->result;
00883 }
00884
00885 #endif