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