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 void
00188 parser_ref (Parser *parser)
00189 {
00190 parser->refcount += 1;
00191 }
00192
00193 void
00194 parser_unref (Parser *parser)
00195 {
00196 parser->refcount -= 1;
00197 if (parser->refcount == 0)
00198 {
00199 if (parser->result)
00200 node_info_unref (parser->result);
00201
00202 g_free (parser);
00203 }
00204 }
00205
00206 gboolean
00207 parser_check_doctype (Parser *parser,
00208 const char *doctype,
00209 GError **error)
00210 {
00211 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00212
00213 if (strcmp (doctype, "dbus_description") != 0)
00214 {
00215 g_set_error (error,
00216 G_MARKUP_ERROR,
00217 G_MARKUP_ERROR_PARSE,
00218 "D-BUS description file has the wrong document type %s, use dbus_description",
00219 doctype);
00220 return FALSE;
00221 }
00222 else
00223 return TRUE;
00224 }
00225
00226 static gboolean
00227 parse_node (Parser *parser,
00228 const char *element_name,
00229 const char **attribute_names,
00230 const char **attribute_values,
00231 GError **error)
00232 {
00233 const char *name;
00234 NodeInfo *node;
00235
00236 if (parser->interface ||
00237 parser->method ||
00238 parser->signal ||
00239 parser->arg)
00240 {
00241 g_set_error (error, G_MARKUP_ERROR,
00242 G_MARKUP_ERROR_PARSE,
00243 _("Can't put a <%s> element here"),
00244 element_name);
00245 return FALSE;
00246 }
00247
00248 name = NULL;
00249 if (!locate_attributes (element_name, attribute_names,
00250 attribute_values, error,
00251 "name", &name,
00252 NULL))
00253 return FALSE;
00254
00255
00256 if (parser->node_stack != NULL && name == NULL)
00257 {
00258 g_set_error (error, G_MARKUP_ERROR,
00259 G_MARKUP_ERROR_PARSE,
00260 _("\"%s\" attribute required on <%s> element "),
00261 "name", element_name);
00262 return FALSE;
00263 }
00264
00265
00266 node = node_info_new (name);
00267
00268 if (parser->node_stack != NULL)
00269 {
00270 node_info_add_node (parser->node_stack->data,
00271 node);
00272 }
00273
00274 parser->node_stack = g_slist_prepend (parser->node_stack,
00275 node);
00276
00277 return TRUE;
00278 }
00279
00280 static gboolean
00281 parse_interface (Parser *parser,
00282 const char *element_name,
00283 const char **attribute_names,
00284 const char **attribute_values,
00285 GError **error)
00286 {
00287 const char *name;
00288 InterfaceInfo *iface;
00289 NodeInfo *top;
00290
00291 if (parser->interface ||
00292 parser->method ||
00293 parser->signal ||
00294 parser->arg ||
00295 (parser->node_stack == NULL))
00296 {
00297 g_set_error (error, G_MARKUP_ERROR,
00298 G_MARKUP_ERROR_PARSE,
00299 _("Can't put a <%s> element here"),
00300 element_name);
00301 return FALSE;
00302 }
00303
00304 name = NULL;
00305 if (!locate_attributes (element_name, attribute_names,
00306 attribute_values, error,
00307 "name", &name,
00308 NULL))
00309 return FALSE;
00310
00311 if (name == NULL)
00312 {
00313 g_set_error (error, G_MARKUP_ERROR,
00314 G_MARKUP_ERROR_PARSE,
00315 _("\"%s\" attribute required on <%s> element "),
00316 "name", element_name);
00317 return FALSE;
00318 }
00319
00320 top = parser->node_stack->data;
00321
00322 iface = interface_info_new (name);
00323 node_info_add_interface (top, iface);
00324 interface_info_unref (iface);
00325
00326 parser->interface = iface;
00327
00328 return TRUE;
00329 }
00330
00331 static gboolean
00332 parse_method (Parser *parser,
00333 const char *element_name,
00334 const char **attribute_names,
00335 const char **attribute_values,
00336 GError **error)
00337 {
00338 const char *name;
00339 MethodInfo *method;
00340 NodeInfo *top;
00341
00342 if (parser->interface == NULL ||
00343 parser->node_stack == NULL ||
00344 parser->method ||
00345 parser->signal ||
00346 parser->arg)
00347 {
00348 g_set_error (error, G_MARKUP_ERROR,
00349 G_MARKUP_ERROR_PARSE,
00350 _("Can't put a <%s> element here"),
00351 element_name);
00352 return FALSE;
00353 }
00354
00355 name = NULL;
00356 if (!locate_attributes (element_name, attribute_names,
00357 attribute_values, error,
00358 "name", &name,
00359 NULL))
00360 return FALSE;
00361
00362 if (name == NULL)
00363 {
00364 g_set_error (error, G_MARKUP_ERROR,
00365 G_MARKUP_ERROR_PARSE,
00366 _("\"%s\" attribute required on <%s> element "),
00367 "name", element_name);
00368 return FALSE;
00369 }
00370
00371 top = parser->node_stack->data;
00372
00373 method = method_info_new (name);
00374 interface_info_add_method (parser->interface, method);
00375 method_info_unref (method);
00376
00377 parser->method = method;
00378
00379 return TRUE;
00380 }
00381
00382 static gboolean
00383 parse_signal (Parser *parser,
00384 const char *element_name,
00385 const char **attribute_names,
00386 const char **attribute_values,
00387 GError **error)
00388 {
00389 const char *name;
00390 SignalInfo *signal;
00391 NodeInfo *top;
00392
00393 if (parser->interface == NULL ||
00394 parser->node_stack == NULL ||
00395 parser->signal ||
00396 parser->signal ||
00397 parser->arg)
00398 {
00399 g_set_error (error, G_MARKUP_ERROR,
00400 G_MARKUP_ERROR_PARSE,
00401 _("Can't put a <%s> element here"),
00402 element_name);
00403 return FALSE;
00404 }
00405
00406 name = NULL;
00407 if (!locate_attributes (element_name, attribute_names,
00408 attribute_values, error,
00409 "name", &name,
00410 NULL))
00411 return FALSE;
00412
00413 if (name == NULL)
00414 {
00415 g_set_error (error, G_MARKUP_ERROR,
00416 G_MARKUP_ERROR_PARSE,
00417 _("\"%s\" attribute required on <%s> element "),
00418 "name", element_name);
00419 return FALSE;
00420 }
00421
00422 top = parser->node_stack->data;
00423
00424 signal = signal_info_new (name);
00425 interface_info_add_signal (parser->interface, signal);
00426 signal_info_unref (signal);
00427
00428 parser->signal = signal;
00429
00430 return TRUE;
00431 }
00432
00433 static int
00434 basic_type_from_string (const char *str)
00435 {
00436 if (strcmp (str, "string") == 0)
00437 return DBUS_TYPE_STRING;
00438 else if (strcmp (str, "int32") == 0)
00439 return DBUS_TYPE_INT32;
00440 else if (strcmp (str, "uint32") == 0)
00441 return DBUS_TYPE_UINT32;
00442 else if (strcmp (str, "int64") == 0)
00443 return DBUS_TYPE_INT64;
00444 else if (strcmp (str, "uint64") == 0)
00445 return DBUS_TYPE_UINT64;
00446 else if (strcmp (str, "double") == 0)
00447 return DBUS_TYPE_DOUBLE;
00448 else if (strcmp (str, "byte") == 0)
00449 return DBUS_TYPE_BYTE;
00450 else if (strcmp (str, "boolean") == 0)
00451 return DBUS_TYPE_BOOLEAN;
00452 else if (strcmp (str, "byte") == 0)
00453 return DBUS_TYPE_BYTE;
00454 else if (strcmp (str, "object") == 0)
00455 return DBUS_TYPE_OBJECT_PATH;
00456 else
00457 return DBUS_TYPE_INVALID;
00458 }
00459
00460 static int
00461 type_from_string (const char *str)
00462 {
00463 return basic_type_from_string (str);
00464 }
00465
00466 static gboolean
00467 parse_arg (Parser *parser,
00468 const char *element_name,
00469 const char **attribute_names,
00470 const char **attribute_values,
00471 GError **error)
00472 {
00473 const char *name;
00474 const char *type;
00475 const char *direction;
00476 ArgDirection dir;
00477 int t;
00478 ArgInfo *arg;
00479
00480 if (!(parser->method || parser->signal) ||
00481 parser->node_stack == NULL ||
00482 parser->arg)
00483 {
00484 g_set_error (error, G_MARKUP_ERROR,
00485 G_MARKUP_ERROR_PARSE,
00486 _("Can't put a <%s> element here"),
00487 element_name);
00488 return FALSE;
00489 }
00490
00491 name = NULL;
00492 if (!locate_attributes (element_name, attribute_names,
00493 attribute_values, error,
00494 "name", &name,
00495 "type", &type,
00496 "direction", &direction,
00497 NULL))
00498 return FALSE;
00499
00500
00501
00502 if (type == NULL)
00503 {
00504 g_set_error (error, G_MARKUP_ERROR,
00505 G_MARKUP_ERROR_PARSE,
00506 _("\"%s\" attribute required on <%s> element "),
00507 "type", element_name);
00508 return FALSE;
00509 }
00510
00511 if (direction == NULL)
00512 {
00513
00514 if (parser->method)
00515 direction = "in";
00516 else if (parser->signal)
00517 direction = "out";
00518 else
00519 g_assert_not_reached ();
00520 }
00521
00522 if (strcmp (direction, "in") == 0)
00523 dir = ARG_IN;
00524 else if (strcmp (direction, "out") == 0)
00525 dir = ARG_OUT;
00526 else
00527 {
00528 g_set_error (error, G_MARKUP_ERROR,
00529 G_MARKUP_ERROR_PARSE,
00530 _("\"%s\" attribute on <%s> has value \"in\" or \"out\""),
00531 "direction", element_name);
00532 return FALSE;
00533 }
00534
00535 t = type_from_string (type);
00536
00537 arg = arg_info_new (name, dir, t);
00538 if (parser->method)
00539 method_info_add_arg (parser->method, arg);
00540 else if (parser->signal)
00541 signal_info_add_arg (parser->signal, arg);
00542 else
00543 g_assert_not_reached ();
00544
00545 arg_info_unref (arg);
00546
00547 parser->arg = arg;
00548
00549 return TRUE;
00550 }
00551
00552 gboolean
00553 parser_start_element (Parser *parser,
00554 const char *element_name,
00555 const char **attribute_names,
00556 const char **attribute_values,
00557 GError **error)
00558 {
00559 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00560
00561 if (ELEMENT_IS ("node"))
00562 {
00563 if (!parse_node (parser, element_name, attribute_names,
00564 attribute_values, error))
00565 return FALSE;
00566 }
00567 else if (ELEMENT_IS ("interface"))
00568 {
00569 if (!parse_interface (parser, element_name, attribute_names,
00570 attribute_values, error))
00571 return FALSE;
00572 }
00573 else if (ELEMENT_IS ("method"))
00574 {
00575 if (!parse_method (parser, element_name, attribute_names,
00576 attribute_values, error))
00577 return FALSE;
00578 }
00579 else if (ELEMENT_IS ("signal"))
00580 {
00581 if (!parse_signal (parser, element_name, attribute_names,
00582 attribute_values, error))
00583 return FALSE;
00584 }
00585 else if (ELEMENT_IS ("arg"))
00586 {
00587 if (!parse_arg (parser, element_name, attribute_names,
00588 attribute_values, error))
00589 return FALSE;
00590 }
00591 else
00592 {
00593 g_set_error (error, G_MARKUP_ERROR,
00594 G_MARKUP_ERROR_PARSE,
00595 _("Element <%s> not recognized"),
00596 element_name);
00597 }
00598
00599 return TRUE;
00600 }
00601
00602 gboolean
00603 parser_end_element (Parser *parser,
00604 const char *element_name,
00605 GError **error)
00606 {
00607 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00608
00609 if (ELEMENT_IS ("interface"))
00610 {
00611 parser->interface = NULL;
00612 }
00613 else if (ELEMENT_IS ("method"))
00614 {
00615 parser->method = NULL;
00616 }
00617 else if (ELEMENT_IS ("signal"))
00618 {
00619 parser->signal = NULL;
00620 }
00621 else if (ELEMENT_IS ("arg"))
00622 {
00623 parser->arg = NULL;
00624 }
00625 else if (ELEMENT_IS ("node"))
00626 {
00627 NodeInfo *top;
00628
00629 g_assert (parser->node_stack != NULL);
00630 top = parser->node_stack->data;
00631
00632 parser->node_stack = g_slist_remove (parser->node_stack,
00633 top);
00634
00635 if (parser->node_stack == NULL)
00636 parser->result = top;
00637 }
00638 else
00639 g_assert_not_reached ();
00640
00641 return TRUE;
00642 }
00643
00644 gboolean
00645 parser_content (Parser *parser,
00646 const char *content,
00647 int len,
00648 GError **error)
00649 {
00650 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00651
00652 return TRUE;
00653 }
00654
00655 gboolean
00656 parser_finished (Parser *parser,
00657 GError **error)
00658 {
00659 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
00660
00661 return TRUE;
00662 }
00663
00664 NodeInfo*
00665 parser_get_nodes (Parser *parser)
00666 {
00667 return parser->result;
00668 }
00669
00670 #endif