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-gidl.h"
00025 #include <string.h>
00026
00027 #include <libintl.h>
00028 #define _(x) gettext ((x))
00029 #define N_(x) x
00030
00031 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00032
00033 #define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0)
00034
00035 typedef struct
00036 {
00037 const char *name;
00038 const char **retloc;
00039 } LocateAttr;
00040
00041 static gboolean
00042 locate_attributes (const char *element_name,
00043 const char **attribute_names,
00044 const char **attribute_values,
00045 GError **error,
00046 const char *first_attribute_name,
00047 const char **first_attribute_retloc,
00048 ...)
00049 {
00050 va_list args;
00051 const char *name;
00052 const char **retloc;
00053 int n_attrs;
00054 #define MAX_ATTRS 24
00055 LocateAttr attrs[MAX_ATTRS];
00056 gboolean retval;
00057 int i;
00058
00059 g_return_val_if_fail (first_attribute_name != NULL, FALSE);
00060 g_return_val_if_fail (first_attribute_retloc != NULL, FALSE);
00061
00062 retval = TRUE;
00063
00064 n_attrs = 1;
00065 attrs[0].name = first_attribute_name;
00066 attrs[0].retloc = first_attribute_retloc;
00067 *first_attribute_retloc = NULL;
00068
00069 va_start (args, first_attribute_retloc);
00070
00071 name = va_arg (args, const char*);
00072 retloc = va_arg (args, const char**);
00073
00074 while (name != NULL)
00075 {
00076 g_return_val_if_fail (retloc != NULL, FALSE);
00077
00078 g_assert (n_attrs < MAX_ATTRS);
00079
00080 attrs[n_attrs].name = name;
00081 attrs[n_attrs].retloc = retloc;
00082 n_attrs += 1;
00083 *retloc = NULL;
00084
00085 name = va_arg (args, const char*);
00086 retloc = va_arg (args, const char**);
00087 }
00088
00089 va_end (args);
00090
00091 if (!retval)
00092 return retval;
00093
00094 i = 0;
00095 while (attribute_names[i])
00096 {
00097 int j;
00098 gboolean found;
00099
00100 found = FALSE;
00101 j = 0;
00102 while (j < n_attrs)
00103 {
00104 if (strcmp (attrs[j].name, attribute_names[i]) == 0)
00105 {
00106 retloc = attrs[j].retloc;
00107
00108 if (*retloc != NULL)
00109 {
00110 g_set_error (error,
00111 G_MARKUP_ERROR,
00112 G_MARKUP_ERROR_PARSE,
00113 _("Attribute \"%s\" repeated twice on the same <%s> element"),
00114 attrs[j].name, element_name);
00115 retval = FALSE;
00116 goto out;
00117 }
00118
00119 *retloc = attribute_values[i];
00120 found = TRUE;
00121 }
00122
00123 ++j;
00124 }
00125
00126 if (!found)
00127 {
00128 g_set_error (error,
00129 G_MARKUP_ERROR,
00130 G_MARKUP_ERROR_PARSE,
00131 _("Attribute \"%s\" is invalid on <%s> element in this context"),
00132 attribute_names[i], element_name);
00133 retval = FALSE;
00134 goto out;
00135 }
00136
00137 ++i;
00138 }
00139
00140 out:
00141 return retval;
00142 }
00143
00144 static gboolean
00145 check_no_attributes (const char *element_name,
00146 const char **attribute_names,
00147 const char **attribute_values,
00148 GError **error)
00149 {
00150 if (attribute_names[0] != NULL)
00151 {
00152 g_set_error (error,
00153 G_MARKUP_ERROR,
00154 G_MARKUP_ERROR_PARSE,
00155 _("Attribute \"%s\" is invalid on <%s> element in this context"),
00156 attribute_names[0], element_name);
00157 return FALSE;
00158 }
00159
00160 return TRUE;
00161 }
00162
00163 struct Parser
00164 {
00165 int refcount;
00166
00167 NodeInfo *result;
00168 GSList *node_stack;
00169 InterfaceInfo *interface;
00170 MethodInfo *method;
00171 SignalInfo *signal;
00172 ArgInfo *arg;
00173 };
00174
00175 Parser*
00176 parser_new (void)
00177 {
00178 Parser *parser;
00179
00180 parser = g_new0 (Parser, 1);
00181
00182 parser->refcount = 1;
00183
00184 return parser;
00185 }
00186
00187 Parser *
00188 parser_ref (Parser *parser)
00189 {
00190 parser->refcount += 1;
00191
00192 return parser;
00193 }
00194
00195 void
00196 parser_unref (Parser *parser)
00197 {
00198 parser->refcount -= 1;
00199 if (parser->refcount == 0)
00200 {
00201 if (parser->result)
00202 node_info_unref (parser->result);
00203
00204 g_free (parser);
00205 }
00206 }
00207
00208 gboolean
00209 parser_check_doctype (Parser *parser,
00210 const char *doctype,
00211 GError **error)
00212 {
00213 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00214
00215 if (strcmp (doctype, "node") != 0)
00216 {
00217 g_set_error (error,
00218 G_MARKUP_ERROR,
00219 G_MARKUP_ERROR_PARSE,
00220 "D-BUS description file has the wrong document type %s, use node or interface",
00221 doctype);
00222 return FALSE;
00223 }
00224 else
00225 return TRUE;
00226 }
00227
00228 static gboolean
00229 parse_node (Parser *parser,
00230 const char *element_name,
00231 const char **attribute_names,
00232 const char **attribute_values,
00233 GError **error)
00234 {
00235 const char *name;
00236 NodeInfo *node;
00237
00238 if (parser->interface ||
00239 parser->method ||
00240 parser->signal ||
00241 parser->arg)
00242 {
00243 g_set_error (error, G_MARKUP_ERROR,
00244 G_MARKUP_ERROR_PARSE,
00245 _("Can't put a <%s> element here"),
00246 element_name);
00247 return FALSE;
00248 }
00249
00250 name = NULL;
00251 if (!locate_attributes (element_name, attribute_names,
00252 attribute_values, error,
00253 "name", &name,
00254 NULL))
00255 return FALSE;
00256
00257
00258 if (parser->node_stack != NULL && name == NULL)
00259 {
00260 g_set_error (error, G_MARKUP_ERROR,
00261 G_MARKUP_ERROR_PARSE,
00262 _("\"%s\" attribute required on <%s> element "),
00263 "name", element_name);
00264 return FALSE;
00265 }
00266
00267
00268 node = node_info_new (name);
00269
00270 if (parser->node_stack != NULL)
00271 {
00272 node_info_add_node (parser->node_stack->data,
00273 node);
00274 }
00275
00276 parser->node_stack = g_slist_prepend (parser->node_stack,
00277 node);
00278
00279 return TRUE;
00280 }
00281
00282 static gboolean
00283 parse_interface (Parser *parser,
00284 const char *element_name,
00285 const char **attribute_names,
00286 const char **attribute_values,
00287 GError **error)
00288 {
00289 const char *name;
00290 InterfaceInfo *iface;
00291 NodeInfo *top;
00292
00293 if (parser->interface ||
00294 parser->method ||
00295 parser->signal ||
00296 parser->arg ||
00297 (parser->node_stack == NULL))
00298 {
00299 g_set_error (error, G_MARKUP_ERROR,
00300 G_MARKUP_ERROR_PARSE,
00301 _("Can't put a <%s> element here"),
00302 element_name);
00303 return FALSE;
00304 }
00305
00306 name = NULL;
00307 if (!locate_attributes (element_name, attribute_names,
00308 attribute_values, error,
00309 "name", &name,
00310 NULL))
00311 return FALSE;
00312
00313 if (name == NULL)
00314 {
00315 g_set_error (error, G_MARKUP_ERROR,
00316 G_MARKUP_ERROR_PARSE,
00317 _("\"%s\" attribute required on <%s> element "),
00318 "name", element_name);
00319 return FALSE;
00320 }
00321
00322 top = parser->node_stack->data;
00323
00324 iface = interface_info_new (name);
00325 node_info_add_interface (top, iface);
00326 interface_info_unref (iface);
00327
00328 parser->interface = iface;
00329
00330 return TRUE;
00331 }
00332
00333 static gboolean
00334 parse_method (Parser *parser,
00335 const char *element_name,
00336 const char **attribute_names,
00337 const char **attribute_values,
00338 GError **error)
00339 {
00340 const char *name;
00341 MethodInfo *method;
00342 NodeInfo *top;
00343
00344 if (parser->interface == NULL ||
00345 parser->node_stack == NULL ||
00346 parser->method ||
00347 parser->signal ||
00348 parser->arg)
00349 {
00350 g_set_error (error, G_MARKUP_ERROR,
00351 G_MARKUP_ERROR_PARSE,
00352 _("Can't put a <%s> element here"),
00353 element_name);
00354 return FALSE;
00355 }
00356
00357 name = NULL;
00358 if (!locate_attributes (element_name, attribute_names,
00359 attribute_values, error,
00360 "name", &name,
00361 NULL))
00362 return FALSE;
00363
00364 if (name == NULL)
00365 {
00366 g_set_error (error, G_MARKUP_ERROR,
00367 G_MARKUP_ERROR_PARSE,
00368 _("\"%s\" attribute required on <%s> element "),
00369 "name", element_name);
00370 return FALSE;
00371 }
00372
00373 top = parser->node_stack->data;
00374
00375 method = method_info_new (name);
00376 interface_info_add_method (parser->interface, method);
00377 method_info_unref (method);
00378
00379 parser->method = method;
00380
00381 return TRUE;
00382 }
00383
00384 static gboolean
00385 parse_signal (Parser *parser,
00386 const char *element_name,
00387 const char **attribute_names,
00388 const char **attribute_values,
00389 GError **error)
00390 {
00391 const char *name;
00392 SignalInfo *signal;
00393 NodeInfo *top;
00394
00395 if (parser->interface == NULL ||
00396 parser->node_stack == NULL ||
00397 parser->signal ||
00398 parser->signal ||
00399 parser->arg)
00400 {
00401 g_set_error (error, G_MARKUP_ERROR,
00402 G_MARKUP_ERROR_PARSE,
00403 _("Can't put a <%s> element here"),
00404 element_name);
00405 return FALSE;
00406 }
00407
00408 name = NULL;
00409 if (!locate_attributes (element_name, attribute_names,
00410 attribute_values, error,
00411 "name", &name,
00412 NULL))
00413 return FALSE;
00414
00415 if (name == NULL)
00416 {
00417 g_set_error (error, G_MARKUP_ERROR,
00418 G_MARKUP_ERROR_PARSE,
00419 _("\"%s\" attribute required on <%s> element "),
00420 "name", element_name);
00421 return FALSE;
00422 }
00423
00424 top = parser->node_stack->data;
00425
00426 signal = signal_info_new (name);
00427 interface_info_add_signal (parser->interface, signal);
00428 signal_info_unref (signal);
00429
00430 parser->signal = signal;
00431
00432 return TRUE;
00433 }
00434
00435 static int
00436 basic_type_from_string (const char *str)
00437 {
00438 if (strcmp (str, "string") == 0)
00439 return DBUS_TYPE_STRING;
00440 else if (strcmp (str, "int32") == 0)
00441 return DBUS_TYPE_INT32;
00442 else if (strcmp (str, "uint32") == 0)
00443 return DBUS_TYPE_UINT32;
00444 else if (strcmp (str, "int64") == 0)
00445 return DBUS_TYPE_INT64;
00446 else if (strcmp (str, "uint64") == 0)
00447 return DBUS_TYPE_UINT64;
00448 else if (strcmp (str, "double") == 0)
00449 return DBUS_TYPE_DOUBLE;
00450 else if (strcmp (str, "byte") == 0)
00451 return DBUS_TYPE_BYTE;
00452 else if (strcmp (str, "boolean") == 0)
00453 return DBUS_TYPE_BOOLEAN;
00454 else if (strcmp (str, "byte") == 0)
00455 return DBUS_TYPE_BYTE;
00456 else if (strcmp (str, "object") == 0)
00457 return DBUS_TYPE_OBJECT_PATH;
00458 else
00459 return DBUS_TYPE_INVALID;
00460 }
00461
00462 static int
00463 type_from_string (const char *str)
00464 {
00465 return basic_type_from_string (str);
00466 }
00467
00468 static gboolean
00469 parse_arg (Parser *parser,
00470 const char *element_name,
00471 const char **attribute_names,
00472 const char **attribute_values,
00473 GError **error)
00474 {
00475 const char *name;
00476 const char *type;
00477 const char *direction;
00478 ArgDirection dir;
00479 int t;
00480 ArgInfo *arg;
00481
00482 if (!(parser->method || parser->signal) ||
00483 parser->node_stack == NULL ||
00484 parser->arg)
00485 {
00486 g_set_error (error, G_MARKUP_ERROR,
00487 G_MARKUP_ERROR_PARSE,
00488 _("Can't put a <%s> element here"),
00489 element_name);
00490 return FALSE;
00491 }
00492
00493 name = NULL;
00494 if (!locate_attributes (element_name, attribute_names,
00495 attribute_values, error,
00496 "name", &name,
00497 "type", &type,
00498 "direction", &direction,
00499 NULL))
00500 return FALSE;
00501
00502
00503
00504 if (type == NULL)
00505 {
00506 g_set_error (error, G_MARKUP_ERROR,
00507 G_MARKUP_ERROR_PARSE,
00508 _("\"%s\" attribute required on <%s> element "),
00509 "type", element_name);
00510 return FALSE;
00511 }
00512
00513 if (direction == NULL)
00514 {
00515
00516 if (parser->method)
00517 direction = "in";
00518 else if (parser->signal)
00519 direction = "out";
00520 else
00521 g_assert_not_reached ();
00522 }
00523
00524 if (strcmp (direction, "in") == 0)
00525 dir = ARG_IN;
00526 else if (strcmp (direction, "out") == 0)
00527 dir = ARG_OUT;
00528 else
00529 {
00530 g_set_error (error, G_MARKUP_ERROR,
00531 G_MARKUP_ERROR_PARSE,
00532 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
00533 "direction", element_name);
00534 return FALSE;
00535 }
00536
00537 t = type_from_string (type);
00538
00539 arg = arg_info_new (name, dir, t);
00540 if (parser->method)
00541 method_info_add_arg (parser->method, arg);
00542 else if (parser->signal)
00543 signal_info_add_arg (parser->signal, arg);
00544 else
00545 g_assert_not_reached ();
00546
00547 arg_info_unref (arg);
00548
00549 parser->arg = arg;
00550
00551 return TRUE;
00552 }
00553
00554 gboolean
00555 parser_start_element (Parser *parser,
00556 const char *element_name,
00557 const char **attribute_names,
00558 const char **attribute_values,
00559 GError **error)
00560 {
00561 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00562
00563 if (ELEMENT_IS ("node"))
00564 {
00565 if (!parse_node (parser, element_name, attribute_names,
00566 attribute_values, error))
00567 return FALSE;
00568 }
00569 else if (ELEMENT_IS ("interface"))
00570 {
00571 if (!parse_interface (parser, element_name, attribute_names,
00572 attribute_values, error))
00573 return FALSE;
00574 }
00575 else if (ELEMENT_IS ("method"))
00576 {
00577 if (!parse_method (parser, element_name, attribute_names,
00578 attribute_values, error))
00579 return FALSE;
00580 }
00581 else if (ELEMENT_IS ("signal"))
00582 {
00583 if (!parse_signal (parser, element_name, attribute_names,
00584 attribute_values, error))
00585 return FALSE;
00586 }
00587 else if (ELEMENT_IS ("arg"))
00588 {
00589 if (!parse_arg (parser, element_name, attribute_names,
00590 attribute_values, error))
00591 return FALSE;
00592 }
00593 else
00594 {
00595 g_set_error (error, G_MARKUP_ERROR,
00596 G_MARKUP_ERROR_PARSE,
00597 _("Element <%s> not recognized"),
00598 element_name);
00599 }
00600
00601 return TRUE;
00602 }
00603
00604 gboolean
00605 parser_end_element (Parser *parser,
00606 const char *element_name,
00607 GError **error)
00608 {
00609 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00610
00611 if (ELEMENT_IS ("interface"))
00612 {
00613 parser->interface = NULL;
00614 }
00615 else if (ELEMENT_IS ("method"))
00616 {
00617 parser->method = NULL;
00618 }
00619 else if (ELEMENT_IS ("signal"))
00620 {
00621 parser->signal = NULL;
00622 }
00623 else if (ELEMENT_IS ("arg"))
00624 {
00625 parser->arg = NULL;
00626 }
00627 else if (ELEMENT_IS ("node"))
00628 {
00629 NodeInfo *top;
00630
00631 g_assert (parser->node_stack != NULL);
00632 top = parser->node_stack->data;
00633
00634 parser->node_stack = g_slist_remove (parser->node_stack,
00635 top);
00636
00637 if (parser->node_stack == NULL)
00638 parser->result = top;
00639 }
00640 else
00641 g_assert_not_reached ();
00642
00643 return TRUE;
00644 }
00645
00646 gboolean
00647 parser_content (Parser *parser,
00648 const char *content,
00649 int len,
00650 GError **error)
00651 {
00652 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00653
00654 return TRUE;
00655 }
00656
00657 gboolean
00658 parser_finished (Parser *parser,
00659 GError **error)
00660 {
00661 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00662
00663 return TRUE;
00664 }
00665
00666 NodeInfo*
00667 parser_get_nodes (Parser *parser)
00668 {
00669 return parser->result;
00670 }
00671
00672 #endif