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