diff options
| author | Havoc Pennington <hp@redhat.com> | 2003-09-03 02:08:25 +0000 | 
|---|---|---|
| committer | Havoc Pennington <hp@redhat.com> | 2003-09-03 02:08:25 +0000 | 
| commit | d021cfae6695f0f44102edf758abfc42e2f3c093 (patch) | |
| tree | 77e95134b676c65557962d50a4eab125a40e6d00 | |
| parent | 7b4ac5de11d90e9f7048f057d70d3da5104388b6 (diff) | |
2003-09-01  Havoc Pennington  <hp@pobox.com>
	* glib/dbus-gparser.c: implement
	* glib/dbus-gobject.c: start implementing skeletons support
	* configure.in: when disabling checks/assert, also define
	G_DISABLE_ASSERT and G_DISABLE_CHECKS
| -rw-r--r-- | ChangeLog | 9 | ||||
| -rw-r--r-- | configure.in | 9 | ||||
| -rw-r--r-- | dbus/dbus-marshal.c | 4 | ||||
| -rw-r--r-- | dbus/dbus-protocol.h | 23 | ||||
| -rw-r--r-- | glib/Makefile.am | 6 | ||||
| -rw-r--r-- | glib/dbus-gidl.c | 90 | ||||
| -rw-r--r-- | glib/dbus-gidl.h | 10 | ||||
| -rw-r--r-- | glib/dbus-glib.h | 26 | ||||
| -rw-r--r-- | glib/dbus-gloader-expat.c | 254 | ||||
| -rw-r--r-- | glib/dbus-gobject.c | 780 | ||||
| -rw-r--r-- | glib/dbus-gparser.c | 549 | ||||
| -rw-r--r-- | glib/dbus-gparser.h | 8 | 
12 files changed, 1740 insertions, 28 deletions
| @@ -1,5 +1,14 @@  2003-09-01  Havoc Pennington  <hp@pobox.com> +	* glib/dbus-gparser.c: implement + +	* glib/dbus-gobject.c: start implementing skeletons support + +	* configure.in: when disabling checks/assert, also define +	G_DISABLE_ASSERT and G_DISABLE_CHECKS + +2003-09-01  Havoc Pennington  <hp@pobox.com> +  	* glib/Makefile.am: rearrange a bunch of files and get "make  	check" framework set up diff --git a/configure.in b/configure.in index 3963a5de..1125ef60 100644 --- a/configure.in +++ b/configure.in @@ -54,9 +54,11 @@ if test x$enable_verbose_mode = xyes; then  fi  if test x$enable_asserts = xno; then      AC_DEFINE(DBUS_DISABLE_ASSERT,1,[Disable assertion checking]) +    AC_DEFINE(G_DISABLE_ASSERT,1,[Disable GLib assertion macros])  fi  if test x$enable_checks = xno; then      AC_DEFINE(DBUS_DISABLE_CHECKS,1,[Disable public API sanity checking]) +    AC_DEFINE(G_DISABLE_CHECKS,1,[Disable GLib public API sanity checking])  fi  #### gcc warning flags @@ -545,7 +547,7 @@ AC_SUBST(DBUS_TEST_CFLAGS)  AC_SUBST(DBUS_TEST_LIBS)  # Glib detection -PKG_CHECK_MODULES(DBUS_GLIB, glib-2.0, have_glib=yes, have_glib=no) +PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0, have_glib=yes, have_glib=no)  PKG_CHECK_MODULES(DBUS_GLIB_THREADS, glib-2.0 gthread-2.0, have_glib_threads=yes, have_glib_threads=no)  if test x$have_glib = xno ; then @@ -570,6 +572,11 @@ AC_SUBST(DBUS_GLIB_CFLAGS)  AC_SUBST(DBUS_GLIB_LIBS)  AC_SUBST(DBUS_GLIB_THREADS_LIBS) +DBUS_GLIB_TOOL_CFLAGS=$XML_CFLAGS +DBUS_GLIB_TOOL_LIBS=$XML_LIBS +AC_SUBST(DBUS_GLIB_TOOL_CFLAGS) +AC_SUBST(DBUS_GLIB_TOOL_LIBS) +  # Qt detection  have_qt=no  AC_MSG_CHECKING([for qglobal.h]) diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 5297cb67..c542ee8b 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -1473,7 +1473,8 @@ _dbus_demarshal_string_array (const DBusString   *str,  #define VERBOSE_DECOMPOSE 0  /** - * Demarshals an object path. + * Demarshals an object path.  A path of just "/" is + * represented as an empty vector of strings.   *    * @param str the string containing the data   * @param byte_order the byte order @@ -1556,7 +1557,6 @@ _dbus_demarshal_object_path (const DBusString *str,        i = j;      }    _dbus_assert (i == len); -  _dbus_assert (retval[0] != NULL);    *path = retval;    if (path_len) diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index e56ab756..473a1051 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -87,6 +87,18 @@ extern "C" {  #define DBUS_PATH_ORG_FREEDESKTOP_DBUS  "/org/freedesktop/DBus"  #define DBUS_PATH_ORG_FREEDESKTOP_LOCAL "/org/freedesktop/Local" +/* Interfaces, these #define don't do much other than + * catch typos at compile time + */ +#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS  "org.freedesktop.DBus" +#define DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE "org.freedesktop.Introspectable" +   +/* This is a special interface whose methods can only be invoked + * by the local implementation (messages from remote apps aren't + * allowed to specify this interface). + */ +#define DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL "org.freedesktop.Local" +    /* Service owner flags */  #define DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT 0x1  #define DBUS_SERVICE_FLAG_REPLACE_EXISTING     0x2 @@ -101,17 +113,6 @@ extern "C" {  #define DBUS_ACTIVATION_REPLY_ACTIVATED      0x0  #define DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE 0x1 -/* Interfaces, these #define don't do much other than - * catch typos at compile time - */ -#define DBUS_INTERFACE_ORG_FREEDESKTOP_DBUS  "org.freedesktop.DBus" - -/* This is a special interface whose methods can only be invoked - * by the local implementation (messages from remote apps aren't - * allowed to specify this interface). - */ -#define DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL "org.freedesktop.Local" -    #ifdef __cplusplus  }  #endif diff --git a/glib/Makefile.am b/glib/Makefile.am index 3d67db2f..f3b43ed3 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -1,4 +1,4 @@ -INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) -DDBUS_COMPILATION=1 +INCLUDES=-I$(top_srcdir) $(DBUS_CLIENT_CFLAGS) $(DBUS_GLIB_CFLAGS) $(DBUS_GLIB_TOOL_CFLAGS) -DDBUS_COMPILATION=1  dbusincludedir=$(includedir)/dbus-1.0/dbus @@ -10,6 +10,7 @@ dbusinclude_HEADERS=				\  libdbus_glib_1_la_SOURCES = 			\  	dbus-gmain.c				\ +	dbus-gobject.c				\  	dbus-gproxy.c				\  	dbus-gtest.c				\  	dbus-gtest.h				\ @@ -23,12 +24,13 @@ dbus_glib_tool_SOURCES =			\  	dbus-gidl.c				\  	dbus-gidl.h				\  	dbus-glib-tool.c			\ +	dbus-gloader-expat.c			\  	dbus-gparser.c				\  	dbus-gparser.h				\  	dbus-gtool-test.h -dbus_glib_tool_LDADD= libdbus-glib-1.la $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la +dbus_glib_tool_LDADD= $(DBUS_GLIB_TOOL_LIBS) libdbus-glib-1.la $(top_builddir)/dbus/libdbus-1.la  if DBUS_BUILD_TESTS diff --git a/glib/dbus-gidl.c b/glib/dbus-gidl.c index d64e95a7..12468abb 100644 --- a/glib/dbus-gidl.c +++ b/glib/dbus-gidl.c @@ -24,6 +24,13 @@  #include "dbus-gidl.h" +struct NodeInfo +{ +  int refcount; +  char *name; +  GSList *interfaces; +}; +  struct InterfaceInfo  {    int refcount; @@ -55,6 +62,20 @@ struct ArgInfo  };  static void +free_interface_list (GSList **interfaces_p) +{ +  GSList *tmp; +  tmp = *interfaces_p; +  while (tmp != NULL) +    { +      interface_info_unref (tmp->data); +      tmp = tmp->next; +    } +  g_slist_free (*interfaces_p); +  *interfaces_p = NULL; +} + +static void  free_method_list (GSList **methods_p)  {    GSList *tmp; @@ -82,6 +103,59 @@ free_signal_list (GSList **signals_p)    *signals_p = NULL;  } +NodeInfo* +node_info_new (const char *name) +{ +  NodeInfo *info; + +  /* name can be NULL */ +   +  info = g_new0 (NodeInfo, 1); +  info->refcount = 1; +  info->name = g_strdup (name); + +  return info; +} + +void +node_info_ref (NodeInfo *info) +{ +  info->refcount += 1; +} + +void +node_info_unref (NodeInfo *info) +{ +  info->refcount -= 1; +  if (info->refcount == 0) +    { +      free_interface_list (&info->interfaces); +      g_free (info->name); +      g_free (info); +    } +} + +const char* +node_info_get_name (NodeInfo *info) +{ +  return info->name; +} + +GSList* +node_info_get_interfaces (NodeInfo *info) +{ +  return info->interfaces; +} + +void +node_info_add_interface (NodeInfo *info, +                         InterfaceInfo    *interface) +{ +  interface_info_ref (interface); +  info->interfaces = g_slist_append (info->interfaces, interface); +} + +  InterfaceInfo*  interface_info_new (const char *name)  { @@ -90,7 +164,7 @@ interface_info_new (const char *name)    info = g_new0 (InterfaceInfo, 1);    info->refcount = 1;    info->name = g_strdup (name); -   +    return info;  } @@ -113,6 +187,12 @@ interface_info_unref (InterfaceInfo *info)      }  } +const char* +interface_info_get_name (InterfaceInfo *info) +{ +  return info->name; +} +  GSList*  interface_info_get_methods (InterfaceInfo *info)  { @@ -163,7 +243,7 @@ method_info_new (const char *name)    info = g_new0 (MethodInfo, 1);    info->refcount = 1;    info->name = g_strdup (name); -   +    return info;  } @@ -213,7 +293,7 @@ signal_info_new (const char *name)    info = g_new0 (SignalInfo, 1);    info->refcount = 1;    info->name = g_strdup (name); -   +    return info;  } @@ -264,10 +344,12 @@ arg_info_new (const char  *name,    info = g_new0 (ArgInfo, 1);    info->refcount = 1; + +  /* name can be NULL */    info->name = g_strdup (name);    info->direction = direction;    info->type = type; -   +    return info;  } diff --git a/glib/dbus-gidl.h b/glib/dbus-gidl.h index 68649cf3..6e4e207a 100644 --- a/glib/dbus-gidl.h +++ b/glib/dbus-gidl.h @@ -29,6 +29,7 @@  G_BEGIN_DECLS +typedef struct NodeInfo      NodeInfo;  typedef struct InterfaceInfo InterfaceInfo;  typedef struct MethodInfo    MethodInfo;  typedef struct SignalInfo    SignalInfo; @@ -40,9 +41,18 @@ typedef enum    ARG_OUT  } ArgDirection; +NodeInfo*      node_info_new              (const char    *name); +void           node_info_ref              (NodeInfo      *info); +void           node_info_unref            (NodeInfo      *info); +const char*    node_info_get_name         (NodeInfo      *info); +GSList*        node_info_get_interfaces   (NodeInfo      *info); +void           node_info_add_interface    (NodeInfo      *info, +                                           InterfaceInfo *interface); +  InterfaceInfo* interface_info_new         (const char    *name);  void           interface_info_ref         (InterfaceInfo *info);  void           interface_info_unref       (InterfaceInfo *info); +const char*    interface_info_get_name    (InterfaceInfo *info);  GSList*        interface_info_get_methods (InterfaceInfo *info);  GSList*        interface_info_get_signals (InterfaceInfo *info);  void           interface_info_add_method  (InterfaceInfo *info, diff --git a/glib/dbus-glib.h b/glib/dbus-glib.h index 7ca22417..3a87dec2 100644 --- a/glib/dbus-glib.h +++ b/glib/dbus-glib.h @@ -24,7 +24,7 @@  #define DBUS_GLIB_H  #include <dbus/dbus.h> -#include <glib.h> +#include <glib-object.h>  G_BEGIN_DECLS @@ -36,6 +36,30 @@ void dbus_connection_setup_with_g_main (DBusConnection *connection,  void dbus_server_setup_with_g_main     (DBusServer     *server,  					GMainContext   *context); +typedef struct DBusGObjectInfo DBusGObjectInfo; +typedef struct DBusGMethodInfo DBusGMethodInfo; + +struct DBusGMethodInfo +{ +  GCallback                 function; +  DBusHandleMessageFunction marshaller; +  int                       data_offset; +}; + +struct DBusGObjectInfo +{ +  const DBusGMethodInfo *infos; +  const unsigned char *data;     +  void *dbus_internal_padding1; +  void *dbus_internal_padding2; +}; + +void dbus_gobject_class_install_info  (GObjectClass          *object_class, +                                       const DBusGObjectInfo *info); +void dbus_connection_register_gobject (DBusConnection        *connection, +                                       const char            *at_path, +                                       GObject               *object); +  #undef DBUS_INSIDE_DBUS_GLIB_H  G_END_DECLS diff --git a/glib/dbus-gloader-expat.c b/glib/dbus-gloader-expat.c new file mode 100644 index 00000000..050d3532 --- /dev/null +++ b/glib/dbus-gloader-expat.c @@ -0,0 +1,254 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gloader-expat.c  expat XML loader + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#include "dbus-gparser.h" +#include <expat.h> + +static void* +expat_g_malloc (size_t sz) +{ +  return g_malloc (sz); +} + +static void* +expat_g_realloc (void *mem, size_t sz) +{ +  return g_realloc (mem, sz); +} + +static XML_Memory_Handling_Suite memsuite = +{ +  expat_g_malloc, +  expat_g_realloc, +  g_free +}; + +typedef struct +{ +  Parser *parser; +  const char *filename; +  GString *content; +  GError **error; +  gboolean failed; +} ExpatParseContext; + +static dbus_bool_t +process_content (ExpatParseContext *context) +{ +  if (context->failed) +    return FALSE; + +  if (context->content->len > 0) +    { +      if (!parser_content (context->parser, +                           context->content->str, +                           context->content->len, +                           context->error)) +        { +          context->failed = TRUE; +          return FALSE; +        } +      g_string_set_size (context->content, 0); +    } + +  return TRUE; +} + +static void +expat_StartElementHandler (void            *userData, +                           const XML_Char  *name, +                           const XML_Char **atts) +{ +  ExpatParseContext *context = userData; +  int i; +  char **names; +  char **values; + +  /* Expat seems to suck and can't abort the parse if we +   * throw an error. Expat 2.0 is supposed to fix this. +   */ +  if (context->failed) +    return; + +  if (!process_content (context)) +    return; + +  /* "atts" is key, value, key, value, NULL */ +  for (i = 0; atts[i] != NULL; ++i) +    ; /* nothing */ + +  g_assert (i % 2 == 0); +  names = g_new0 (char *, i / 2 + 1); +  values = g_new0 (char *, i / 2 + 1); + +  i = 0; +  while (atts[i] != NULL) +    { +      g_assert (i % 2 == 0); +      names [i / 2] = (char*) atts[i]; +      values[i / 2] = (char*) atts[i+1]; + +      i += 2; +    } + +  if (!parser_start_element (context->parser, +                             name, +                             (const char **) names, +                             (const char **) values, +                             context->error)) +    { +      g_free (names); +      g_free (values); +      context->failed = TRUE; +      return; +    } + +  g_free (names); +  g_free (values); +} + +static void +expat_EndElementHandler (void           *userData, +                         const XML_Char *name) +{ +  ExpatParseContext *context = userData; + +  if (!process_content (context)) +    return; + +  if (!parser_end_element (context->parser, +                           name, +                           context->error)) +    { +      context->failed = TRUE; +      return; +    } +} + +/* s is not 0 terminated. */ +static void +expat_CharacterDataHandler (void           *userData, +                            const XML_Char *s, +                            int             len) +{ +  ExpatParseContext *context = userData; + +  if (context->failed) +    return; + +  g_string_append_len (context->content, +                       s, len); +} + +Parser* +description_load_from_file (const char       *filename, +                            GError          **error) +{ +  char *contents; +  gsize len; +  Parser *parser; +   +  contents = NULL; +  if (!g_file_get_contents (filename, &contents, &len, error)) +    return NULL; + +  parser = description_load_from_string (contents, len, error); +  g_free (contents); + +  return parser; +} + +Parser* +description_load_from_string (const char  *str, +                              int          len, +                              GError     **error) +{ +  XML_Parser expat; +  ExpatParseContext context; +   +  g_return_val_if_fail (error == NULL || *error == NULL, NULL); + +  expat = NULL; +  context.parser = NULL; +  context.error = error; +  context.failed = FALSE; +   +  expat = XML_ParserCreate_MM ("UTF-8", &memsuite, NULL); +  if (expat == NULL) +    g_error ("No memory to create XML parser\n"); + +  context.parser = parser_new (); +  context.content = g_string_new (NULL); +   +  XML_SetUserData (expat, &context); +  XML_SetElementHandler (expat, +                         expat_StartElementHandler, +                         expat_EndElementHandler); +  XML_SetCharacterDataHandler (expat, +                               expat_CharacterDataHandler); +   +  if (!XML_Parse (expat, str, len, TRUE)) +    { +      if (context.error != NULL && +          *context.error == NULL) +        { +            enum XML_Error e; + +            e = XML_GetErrorCode (expat); +            if (e == XML_ERROR_NO_MEMORY) +              g_error ("Not enough memory to parse XML document"); +            else +              g_set_error (error, +                           G_MARKUP_ERROR, +                           G_MARKUP_ERROR_PARSE, +                           "Error in D-BUS description XML, line %d, column %d: %s\n", +                           XML_GetCurrentLineNumber (expat), +                           XML_GetCurrentColumnNumber (expat), +                           XML_ErrorString (e)); +        } +       +        goto failed; +    } +   +  if (context.failed) +    goto failed; + +  if (!parser_finished (context.parser, error)) +    goto failed; + +  XML_ParserFree (expat); +  g_string_free (context.content, TRUE); + +  g_return_val_if_fail (error == NULL || *error == NULL, NULL);   +  return context.parser; + + failed: +  g_return_val_if_fail (error == NULL || *error != NULL, NULL); + +  g_string_free (context.content, TRUE); +  if (expat) +    XML_ParserFree (expat); +  if (context.parser) +    parser_unref (context.parser); +  return NULL; +} diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c new file mode 100644 index 00000000..aa53265b --- /dev/null +++ b/glib/dbus-gobject.c @@ -0,0 +1,780 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-gobject.c Exporting a GObject remotely + * + * Copyright (C) 2003 Red Hat, Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + * + */ + +#include <config.h> +#include "dbus-glib.h" +#include "dbus-gtest.h" +#include <string.h> + +/** + * @addtogroup DBusGLibInternals + * @{ + */ + +static GStaticMutex info_hash_mutex = G_STATIC_MUTEX_INIT; +static GHashTable *info_hash = NULL; + +static char* +javacaps_to_uscore (const char *caps) +{ +  const char *p; +  GString *str; + +  str = g_string_new (NULL); +  p = caps; +  while (*p) +    { +      if (g_ascii_isupper (*p)) +        { +          if (str->len > 0 && +              (str->len < 2 || str->str[str->len-2] != '_')) +            g_string_append_c (str, '_'); +          g_string_append_c (str, g_ascii_tolower (*p)); +        } +      else +        { +          g_string_append_c (str, *p); +        } +      ++p; +    } + +  return g_string_free (str, FALSE); +} + +static char* +uscore_to_javacaps (const char *uscore) +{ +  const char *p; +  GString *str; +  gboolean last_was_uscore; + +  last_was_uscore = TRUE; +   +  str = g_string_new (NULL); +  p = uscore; +  while (*p) +    { +      if (*p == '-' || *p == '_') +        { +          last_was_uscore = TRUE; +        } +      else +        { +          if (last_was_uscore) +            { +              g_string_append_c (str, g_ascii_toupper (*p)); +              last_was_uscore = FALSE; +            } +          else +            g_string_append_c (str, *p); +        } +      ++p; +    } + +  return g_string_free (str, FALSE); +} + +static void +gobject_unregister_function (DBusConnection  *connection, +                             void            *user_data) +{ +  GObject *object; + +  object = G_OBJECT (user_data); + + +} + +static int +gtype_to_dbus_type (GType type) +{ +  switch (type) +    { +    case G_TYPE_CHAR: +    case G_TYPE_UCHAR: +      return DBUS_TYPE_BYTE; +       +    case G_TYPE_BOOLEAN: +      return DBUS_TYPE_BOOLEAN; + +      /* long gets cut to 32 bits so the remote API is consistent +       * on all architectures +       */ +       +    case G_TYPE_LONG: +    case G_TYPE_INT: +      return DBUS_TYPE_INT32; +    case G_TYPE_ULONG: +    case G_TYPE_UINT: +      return DBUS_TYPE_UINT32; + +    case G_TYPE_INT64: +      return DBUS_TYPE_INT64; + +    case G_TYPE_UINT64: +      return DBUS_TYPE_UINT64; +       +    case G_TYPE_FLOAT: +    case G_TYPE_DOUBLE: +      return DBUS_TYPE_DOUBLE; + +    case G_TYPE_STRING: +      return DBUS_TYPE_STRING; + +    default: +      return DBUS_TYPE_INVALID; +    } +} + +static const char * +dbus_type_to_string (int type) +{ +  switch (type) +    { +    case DBUS_TYPE_INVALID: +      return "invalid"; +    case DBUS_TYPE_NIL: +      return "nil"; +    case DBUS_TYPE_BOOLEAN: +      return "boolean"; +    case DBUS_TYPE_INT32: +      return "int32"; +    case DBUS_TYPE_UINT32: +      return "uint32"; +    case DBUS_TYPE_DOUBLE: +      return "double"; +    case DBUS_TYPE_STRING: +      return "string"; +    case DBUS_TYPE_NAMED: +      return "named"; +    case DBUS_TYPE_ARRAY: +      return "array"; +    case DBUS_TYPE_DICT: +      return "dict"; +    default: +      return "unknown"; +    } +} + +static DBusHandlerResult +handle_introspect (DBusConnection *connection, +                   DBusMessage    *message, +                   GObject        *object) +{ +  GString *xml; +  GParamSpec **specs; +  unsigned int n_specs; +  unsigned int i; +  GType last_type; +  DBusMessage *ret; +   +  xml = g_string_new (NULL); + +  g_string_append (xml, "<node>\n"); + +  last_type = G_TYPE_INVALID; + +  specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), +                                          &n_specs); + +  i = 0; +  while (i < n_specs) +    { +      GParamSpec *spec = specs[i]; +      gboolean can_set; +      gboolean can_get; +      char *s; +      int dbus_type; +       +      dbus_type = gtype_to_dbus_type (G_PARAM_SPEC_VALUE_TYPE (spec)); +      if (dbus_type == DBUS_TYPE_INVALID) +        goto next; +       +      if (spec->owner_type != last_type) +	{ +          if (last_type != G_TYPE_INVALID) +            g_string_append (xml, "  </interface>\n"); + + +          /* FIXME what should the namespace on the interface be in +           * general?  should people be able to set it for their +           * objects? +           */ +           +          g_string_append (xml, "  <interface name=\"org.gtk.objects."); +          g_string_append (xml, g_type_name (spec->owner_type)); +          g_string_append (xml, "\">\n"); + +          last_type = spec->owner_type; +	} + +      can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 && +                    (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0); + +      can_get = (spec->flags & G_PARAM_READABLE) != 0; + +      s = uscore_to_javacaps (spec->name); +       +      if (can_set) +        { +          g_string_append (xml, "    <method name=\"set"); +          g_string_append (xml, s); +          g_string_append (xml, "\">\n"); +           +          g_string_append (xml, "      <arg type=\""); +          g_string_append (xml, dbus_type_to_string (dbus_type)); +          g_string_append (xml, "\"/>\n"); +        } + +      if (can_get) +        { +          g_string_append (xml, "    <method name=\"get"); +          g_string_append (xml, s); +          g_string_append (xml, "\">\n"); +           +          g_string_append (xml, "      <arg type=\""); +          g_string_append (xml, dbus_type_to_string (dbus_type)); +          g_string_append (xml, "\" direction=\"out\"/>\n"); +        } + +      g_free (s); + +    next: +      ++i; +    } + +  if (last_type != G_TYPE_INVALID) +    g_string_append (xml, "  </interface>\n"); + +  g_free (specs); + +  /* Close the XML, and send it to the requesting app */ + +  g_string_append (xml, "</node>\n"); + +  ret = dbus_message_new_method_return (message); +  if (ret == NULL) +    g_error ("out of memory"); + +  dbus_message_append_args (message, +                            DBUS_TYPE_STRING, xml->str, +                            DBUS_TYPE_INVALID); + +  dbus_connection_send (connection, message, NULL); +  dbus_message_unref (message); + +  g_string_free (xml, TRUE); + +  return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusMessage* +set_object_property (DBusConnection *connection, +                     DBusMessage    *message, +                     GObject        *object, +                     GParamSpec     *pspec) +{ +  GValue value; +  DBusMessageIter iter; +  int type; +  gboolean can_set; +  DBusMessage *ret; + +  dbus_message_iter_init (message, &iter); +  type = dbus_message_get_type (message); + +  can_set = TRUE; +  switch (type) +    { +    case DBUS_TYPE_BYTE: +      { +        unsigned char b; + +        b = dbus_message_iter_get_byte (&iter); + +        g_value_init (&value, G_TYPE_UCHAR); + +        g_value_set_uchar (&value, b); +      } +      break; +    case DBUS_TYPE_BOOLEAN: +      { +        gboolean b; + +        b = dbus_message_iter_get_boolean (&iter); + +        g_value_init (&value, G_TYPE_BOOLEAN); + +        g_value_set_boolean (&value, b); +      } +      break; +    case DBUS_TYPE_INT32: +      { +        gint32 i; + +        i = dbus_message_iter_get_int32 (&iter); + +        g_value_init (&value, G_TYPE_INT); + +        g_value_set_int (&value, i); +      } +      break; +    case DBUS_TYPE_UINT32: +      { +        guint32 i; + +        i = dbus_message_iter_get_uint32 (&iter); + +        g_value_init (&value, G_TYPE_UINT); + +        g_value_set_uint (&value, i); +      } +      break; +    case DBUS_TYPE_INT64: +      { +        gint64 i; + +        i = dbus_message_iter_get_int64 (&iter); + +        g_value_init (&value, G_TYPE_INT64); + +        g_value_set_int64 (&value, i); +      } +      break; +    case DBUS_TYPE_UINT64: +      { +        guint64 i; + +        i = dbus_message_iter_get_uint64 (&iter); + +        g_value_init (&value, G_TYPE_UINT64); + +        g_value_set_uint64 (&value, i); +      } +      break; +    case DBUS_TYPE_DOUBLE: +      { +        double d; + +        d = dbus_message_iter_get_double (&iter); + +        g_value_init (&value, G_TYPE_DOUBLE); + +        g_value_set_double (&value, d); +      } +      break; +    case DBUS_TYPE_STRING: +      { +        char *s; + +        /* FIXME use a const string accessor */ + +        s = dbus_message_iter_get_string (&iter); + +        g_value_init (&value, G_TYPE_STRING); + +        g_value_set_string (&value, s); + +        g_free (s); +      } +      break; + +      /* FIXME array and other types, especially byte array +       * converted to G_TYPE_STRING +       */ + +    default: +      can_set = FALSE; +      break; +    } + +  /* The g_object_set_property() will transform some types, e.g. it +   * will let you use a uchar to set an int property etc. Note that +   * any error in value range or value conversion will just +   * g_warning(). These GObject skels are not for secure applications. +   */ + +  if (can_set) +    { +      g_object_set_property (object, +                             pspec->name, +                             &value); + +      ret = dbus_message_new_method_return (message); +      if (ret == NULL) +        g_error ("out of memory"); + +      g_value_unset (&value); +    } +  else +    { +      ret = dbus_message_new_error (message, +                                    DBUS_ERROR_INVALID_ARGS, +                                    "Argument's D-BUS type can't be converted to a GType"); +      if (ret == NULL) +        g_error ("out of memory"); +    } + +  return ret; +} + +static DBusMessage* +get_object_property (DBusConnection *connection, +                     DBusMessage    *message, +                     GObject        *object, +                     GParamSpec     *pspec) +{ +  GType value_type; +  gboolean can_get; +  DBusMessage *ret; +  GValue value; +  DBusMessageIter iter; + +  value_type = G_PARAM_SPEC_VALUE_TYPE (pspec); + +  ret = dbus_message_new_method_return (message); +  if (ret == NULL) +    g_error ("out of memory"); + +  can_get = TRUE; +  g_value_init (&value, value_type); +  g_object_get_property (object, pspec->name, &value); + +  value_type = G_VALUE_TYPE (&value); + +  dbus_message_append_iter_init (message, &iter); +   +  switch (value_type) +    { +    case G_TYPE_CHAR: +      dbus_message_iter_append_byte (&iter, +                                     g_value_get_char (&value)); +      break; +    case G_TYPE_UCHAR: +      dbus_message_iter_append_byte (&iter, +                                     g_value_get_uchar (&value)); +      break; +    case G_TYPE_BOOLEAN: +      dbus_message_iter_append_boolean (&iter, +                                        g_value_get_boolean (&value)); +      break; +    case G_TYPE_INT: +      dbus_message_iter_append_int32 (&iter, +                                      g_value_get_int (&value)); +      break; +    case G_TYPE_UINT: +      dbus_message_iter_append_uint32 (&iter, +                                       g_value_get_uint (&value)); +      break; +      /* long gets cut to 32 bits so the remote API is consistent +       * on all architectures +       */ +    case G_TYPE_LONG: +      dbus_message_iter_append_int32 (&iter, +                                      g_value_get_long (&value)); +      break; +    case G_TYPE_ULONG: +      dbus_message_iter_append_uint32 (&iter, +                                       g_value_get_ulong (&value)); +      break; +    case G_TYPE_INT64: +      dbus_message_iter_append_int64 (&iter, +                                      g_value_get_int64 (&value)); +      break; +    case G_TYPE_UINT64: +      dbus_message_iter_append_uint64 (&iter, +                                       g_value_get_uint64 (&value)); +      break; +    case G_TYPE_FLOAT: +      dbus_message_iter_append_double (&iter, +                                       g_value_get_float (&value)); +      break; +    case G_TYPE_DOUBLE: +      dbus_message_iter_append_double (&iter, +                                       g_value_get_double (&value)); +      break; +    case G_TYPE_STRING: +      /* FIXME, the GValue string may not be valid UTF-8 */ +      dbus_message_iter_append_string (&iter, +                                       g_value_get_string (&value)); +      break; +    default: +      can_get = FALSE; +      break; +    } + +  g_value_unset (&value); + +  if (!can_get) +    { +      dbus_message_unref (ret); +      ret = dbus_message_new_error (message, +                                    DBUS_ERROR_UNKNOWN_METHOD, +                                    "Can't convert GType of object property to a D-BUS type"); +    } + +  return ret; +} + +static DBusHandlerResult +gobject_message_function (DBusConnection  *connection, +                          DBusMessage     *message, +                          void            *user_data) +{ +  const DBusGObjectInfo *info; +  GParamSpec *pspec; +  GObject *object; +  const char *member; +  gboolean setter; +  gboolean getter; +  char *s; + +  object = G_OBJECT (user_data); + +  if (dbus_message_is_method_call (message, +                                   DBUS_INTERFACE_ORG_FREEDESKTOP_INTROSPECTABLE, +                                   "Introspect")) +    return handle_introspect (connection, message, object); + +  member = dbus_message_get_member (message); + +  /* Try the metainfo, which lets us invoke methods */ + +  g_static_mutex_lock (&info_hash_mutex); +  /* FIXME this needs to walk up the inheritance tree, not +   * just look at the most-derived class +   */ +  info = g_hash_table_lookup (info_hash, +                              G_OBJECT_GET_CLASS (object)); +  g_static_mutex_unlock (&info_hash_mutex); + +  if (info != NULL) +    { + + + +    } + +  /* If no metainfo, we can still do properties and signals +   * via standard GLib introspection +   */ +  setter = (member[0] == 's' && member[1] == 'e' && member[2] == 't'); +  getter = (member[0] == 'g' && member[1] == 'e' && member[2] == 't'); + +  if (!(setter || getter)) +    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + +  s = javacaps_to_uscore (&member[3]); + +  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), +                                        s); + +  g_free (s); + +  if (pspec != NULL) +    { +      DBusMessage *ret; + +      if (setter) +        { +          ret = set_object_property (connection, message, +                                     object, pspec); +        } +      else if (getter) +        { +          ret = get_object_property (connection, message, +                                     object, pspec); +        } +      else +        { +          g_assert_not_reached (); +          ret = NULL; +        } + +      g_assert (ret != NULL); + +      dbus_connection_send (connection, ret, NULL); +      dbus_message_unref (ret); +      return DBUS_HANDLER_RESULT_HANDLED; +    } + +  return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static DBusObjectPathVTable gobject_dbus_vtable = { +  gobject_unregister_function, +  gobject_message_function, +  NULL +}; + +/** @} */ /* end of internals */ + +/** + * @addtogroup DBusGLib + * @{ + */ + +/** + * Install introspection information about the given object class + * sufficient to allow methods on the object to be invoked by name. + * The introspection information is normally generated by + * dbus-glib-tool, then this function is called in the + * class_init() for the object class. + * + * Once introspection information has been installed, instances of the + * object registered with dbus_connection_register_gobject() can have + * their methods invoked remotely. + * + * @param object_class class struct of the object + * @param info introspection data generated by dbus-glib-tool + */ +void +dbus_gobject_class_install_info (GObjectClass          *object_class, +                                 const DBusGObjectInfo *info) +{ +  g_return_if_fail (G_IS_OBJECT_CLASS (object_class)); + +  g_static_mutex_lock (&info_hash_mutex); + +  if (info_hash == NULL) +    { +      info_hash = g_hash_table_new (NULL, NULL); /* direct hash */ +    } + +  g_hash_table_replace (info_hash, object_class, (void*) info); + +  g_static_mutex_unlock (&info_hash_mutex); +} + +static char** +split_path (const char *path) +{ +  int len; +  char **split; +  int n_components; +  int i, j, comp; + +  len = strlen (path); + +  n_components = 0; +  i = 0; +  while (i < len) +    { +      if (path[i] == '/') +        n_components += 1; +      ++i; +    } + +  split = g_new0 (char*, n_components + 1); + +  comp = 0; +  i = 0; +  while (i < len) +    { +      if (path[i] == '/') +        ++i; +      j = i; + +      while (j < len && path[j] != '/') +        ++j; + +      /* Now [i, j) is the path component */ +      g_assert (i < j); +      g_assert (path[i] != '/'); +      g_assert (j == len || path[j] == '/'); + +      split[comp] = g_strndup (&path[i], j - i + 1); + +      split[comp][j-i] = '\0'; + +      ++comp; +      i = j; +    } +  g_assert (i == len); + +  return split; +} + +/** + * Registers a GObject at the given path. Properties, methods, and signals + * of the object can then be accessed remotely. Methods are only available + * if method introspection data has been added to the object's class + * with g_object_class_install_info(). + * + * The registration will be cancelled if either the DBusConnection or + * the GObject gets finalized. + * + * @param connection the D-BUS connection + * @param at_path the path where the object will live (the object's name) + * @param object the object + */ +void +dbus_connection_register_gobject (DBusConnection        *connection, +                                  const char            *at_path, +                                  GObject               *object) +{ +  char **split; + +  g_return_if_fail (connection != NULL); +  g_return_if_fail (at_path != NULL); +  g_return_if_fail (G_IS_OBJECT (object)); + +  split = split_path (at_path); + +  if (!dbus_connection_register_object_path (connection, +                                             (const char**) split, +                                             &gobject_dbus_vtable, +                                             object)) +    g_error ("Failed to register GObject with DBusConnection"); + +  g_strfreev (split); + +  /* FIXME set up memory management (so we break the +   * registration if object or connection vanishes) +   */ +} + +/** @} */ /* end of public API */ + +#ifdef DBUS_BUILD_TESTS + +/** + * @ingroup DBusGLibInternals + * Unit test for GLib GObject integration ("skeletons") + * @returns #TRUE on success. + */ +dbus_bool_t +_dbus_gobject_test (const char *test_data_dir) +{ +  static struct { const char *javacaps; const char *uscore; } name_pairs[] = { +    { "setFoo", "set_foo" }, +    { "foo", "foo" }, +    { "getFooBar", "get_foo_bar" }, +    { "Hello", "hello" }, +    { "frobateUIHandler", "frobate_ui_handler" } +  }; + +  return TRUE; +} + +#endif /* DBUS_BUILD_TESTS */ diff --git a/glib/dbus-gparser.c b/glib/dbus-gparser.c index 6fea4abc..c2b54d31 100644 --- a/glib/dbus-gparser.c +++ b/glib/dbus-gparser.c @@ -22,11 +22,152 @@   */  #include "dbus-gparser.h"  #include "dbus-gidl.h" +#include <string.h> + +#include <libintl.h> +#define _(x) gettext ((x)) +#define N_(x) x + +#define ELEMENT_IS(name) (strcmp (element_name, (name)) == 0) + +typedef struct +{ +  const char  *name; +  const char **retloc; +} LocateAttr; + +static gboolean +locate_attributes (const char  *element_name, +                   const char **attribute_names, +                   const char **attribute_values, +                   GError     **error, +                   const char  *first_attribute_name, +                   const char **first_attribute_retloc, +                   ...) +{ +  va_list args; +  const char *name; +  const char **retloc; +  int n_attrs; +#define MAX_ATTRS 24 +  LocateAttr attrs[MAX_ATTRS]; +  gboolean retval; +  int i; + +  g_return_val_if_fail (first_attribute_name != NULL, FALSE); +  g_return_val_if_fail (first_attribute_retloc != NULL, FALSE); + +  retval = TRUE; + +  n_attrs = 1; +  attrs[0].name = first_attribute_name; +  attrs[0].retloc = first_attribute_retloc; +  *first_attribute_retloc = NULL; +   +  va_start (args, first_attribute_retloc); + +  name = va_arg (args, const char*); +  retloc = va_arg (args, const char**); + +  while (name != NULL) +    { +      g_return_val_if_fail (retloc != NULL, FALSE); + +      g_assert (n_attrs < MAX_ATTRS); +       +      attrs[n_attrs].name = name; +      attrs[n_attrs].retloc = retloc; +      n_attrs += 1; +      *retloc = NULL;       + +      name = va_arg (args, const char*); +      retloc = va_arg (args, const char**); +    } + +  va_end (args); + +  if (!retval) +    return retval; + +  i = 0; +  while (attribute_names[i]) +    { +      int j; +      gboolean found; + +      found = FALSE; +      j = 0; +      while (j < n_attrs) +        { +          if (strcmp (attrs[j].name, attribute_names[i]) == 0) +            { +              retloc = attrs[j].retloc; + +              if (*retloc != NULL) +                { +                  g_set_error (error, +                               G_MARKUP_ERROR, +                               G_MARKUP_ERROR_PARSE, +                               _("Attribute \"%s\" repeated twice on the same <%s> element"), +                               attrs[j].name, element_name); +                  retval = FALSE; +                  goto out; +                } + +              *retloc = attribute_values[i]; +              found = TRUE; +            } + +          ++j; +        } + +      if (!found) +        { +          g_set_error (error, +                       G_MARKUP_ERROR, +                       G_MARKUP_ERROR_PARSE, +                       _("Attribute \"%s\" is invalid on <%s> element in this context"), +                       attribute_names[i], element_name); +          retval = FALSE; +          goto out; +        } + +      ++i; +    } + + out: +  return retval; +} + +static gboolean +check_no_attributes (const char  *element_name, +                     const char **attribute_names, +                     const char **attribute_values, +                     GError     **error) +{ +  if (attribute_names[0] != NULL) +    { +      g_set_error (error, +                   G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("Attribute \"%s\" is invalid on <%s> element in this context"), +                   attribute_names[0], element_name); +      return FALSE; +    } + +  return TRUE; +}  struct Parser  {    int refcount; +  NodeInfo *result; /* Filled in when we pop the last node */ +  GSList *node_stack; +  InterfaceInfo *interface; +  MethodInfo *method; +  SignalInfo *signal; +  ArgInfo *arg;  };  Parser* @@ -53,7 +194,8 @@ parser_unref (Parser *parser)    parser->refcount -= 1;    if (parser->refcount == 0)      { -       +      if (parser->result) +        node_info_unref (parser->result);        g_free (parser);      } @@ -64,11 +206,12 @@ parser_check_doctype (Parser      *parser,                        const char  *doctype,                        GError     **error)  { -  g_return_val_if_fail (error == NULL || *error == NULL); +  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);    if (strcmp (doctype, "dbus_description") != 0)      {        g_set_error (error, +                   G_MARKUP_ERROR,                     G_MARKUP_ERROR_PARSE,                     "D-BUS description file has the wrong document type %s, use dbus_description",                     doctype); @@ -78,6 +221,324 @@ parser_check_doctype (Parser      *parser,      return TRUE;  } +static gboolean +parse_node (Parser      *parser, +            const char  *element_name, +            const char **attribute_names, +            const char **attribute_values, +            GError     **error) +{ +  const char *name; +  NodeInfo *node; +   +  if (parser->interface || +      parser->method || +      parser->signal || +      parser->arg) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("Can't put a <%s> element here"), +                   element_name); +      return FALSE;       +    } + +  name = NULL; +  if (!locate_attributes (element_name, attribute_names, +                          attribute_values, error, +                          "name", &name, +                          NULL)) +    return FALSE; + +  /* Only the root node can have no name */ +  if (parser->node_stack != NULL && name == NULL) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("\"%s\" attribute required on <%s> element "), +                   "name", element_name); +      return FALSE; +    } + +  node = node_info_new (name); +  parser->node_stack = g_slist_prepend (parser->node_stack, +                                        node); +   +  return TRUE; +} + +static gboolean +parse_interface (Parser      *parser, +                 const char  *element_name, +                 const char **attribute_names, +                 const char **attribute_values, +                 GError     **error) +{ +  const char *name; +  InterfaceInfo *iface; +  NodeInfo *top; +   +  if (parser->interface || +      parser->method || +      parser->signal || +      parser->arg || +      (parser->node_stack == NULL)) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("Can't put a <%s> element here"), +                   element_name); +      return FALSE;       +    } + +  name = NULL; +  if (!locate_attributes (element_name, attribute_names, +                          attribute_values, error, +                          "name", &name, +                          NULL)) +    return FALSE; + +  if (name == NULL) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("\"%s\" attribute required on <%s> element "), +                   "name", element_name); +      return FALSE; +    } + +  top = parser->node_stack->data; +   +  iface = interface_info_new (name); +  node_info_add_interface (top, iface); +  interface_info_unref (iface); + +  parser->interface = iface; +   +  return TRUE; +} + +static gboolean +parse_method (Parser      *parser, +              const char  *element_name, +              const char **attribute_names, +              const char **attribute_values, +              GError     **error) +{ +  const char *name; +  MethodInfo *method; +  NodeInfo *top; +   +  if (parser->interface == NULL || +      parser->node_stack == NULL || +      parser->method || +      parser->signal || +      parser->arg) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("Can't put a <%s> element here"), +                   element_name); +      return FALSE;       +    } + +  name = NULL; +  if (!locate_attributes (element_name, attribute_names, +                          attribute_values, error, +                          "name", &name, +                          NULL)) +    return FALSE; + +  if (name == NULL) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("\"%s\" attribute required on <%s> element "), +                   "name", element_name); +      return FALSE; +    } + +  top = parser->node_stack->data; +   +  method = method_info_new (name); +  interface_info_add_method (parser->interface, method); +  method_info_unref (method); + +  parser->method = method; +   +  return TRUE; +} + +static gboolean +parse_signal (Parser      *parser, +              const char  *element_name, +              const char **attribute_names, +              const char **attribute_values, +              GError     **error) +{ +  const char *name; +  SignalInfo *signal; +  NodeInfo *top; +   +  if (parser->interface == NULL || +      parser->node_stack == NULL || +      parser->signal || +      parser->signal || +      parser->arg) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("Can't put a <%s> element here"), +                   element_name); +      return FALSE;       +    } + +  name = NULL; +  if (!locate_attributes (element_name, attribute_names, +                          attribute_values, error, +                          "name", &name, +                          NULL)) +    return FALSE; + +  if (name == NULL) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("\"%s\" attribute required on <%s> element "), +                   "name", element_name); +      return FALSE; +    } + +  top = parser->node_stack->data; +   +  signal = signal_info_new (name); +  interface_info_add_signal (parser->interface, signal); +  signal_info_unref (signal); + +  parser->signal = signal; +   +  return TRUE; +} + +static int +basic_type_from_string (const char *str) +{ +  if (strcmp (str, "string") == 0) +    return DBUS_TYPE_STRING; +  else if (strcmp (str, "int32") == 0) +    return DBUS_TYPE_INT32; +  else if (strcmp (str, "uint32") == 0) +    return DBUS_TYPE_UINT32; +  else if (strcmp (str, "int64") == 0) +    return DBUS_TYPE_INT64; +  else if (strcmp (str, "uint64") == 0) +    return DBUS_TYPE_UINT64; +  else if (strcmp (str, "double") == 0) +    return DBUS_TYPE_DOUBLE; +  else if (strcmp (str, "byte") == 0) +    return DBUS_TYPE_BYTE; +  else if (strcmp (str, "boolean") == 0) +    return DBUS_TYPE_BOOLEAN; +  else if (strcmp (str, "byte") == 0) +    return DBUS_TYPE_BYTE; +  else if (strcmp (str, "object") == 0) +    return DBUS_TYPE_OBJECT_PATH; +  else +    return DBUS_TYPE_INVALID; +} + +static int +type_from_string (const char *str) +{ +  return basic_type_from_string (str); +} + +static gboolean +parse_arg (Parser      *parser, +           const char  *element_name, +           const char **attribute_names, +           const char **attribute_values, +           GError     **error) +{ +  const char *name; +  const char *type; +  const char *direction; +  ArgDirection dir; +  int t; +  ArgInfo *arg; +   +  if (!(parser->method || parser->signal) || +      parser->node_stack == NULL || +      parser->arg) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("Can't put a <%s> element here"), +                   element_name); +      return FALSE;       +    } + +  name = NULL; +  if (!locate_attributes (element_name, attribute_names, +                          attribute_values, error, +                          "name", &name, +                          "type", &type, +                          "direction", &direction, +                          NULL)) +    return FALSE; + +  /* name can be null for args */ +   +  if (type == NULL) +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("\"%s\" attribute required on <%s> element "), +                   "type", element_name); +      return FALSE; +    } + +  if (direction == NULL) +    { +      /* methods default to in, signal to out */ +      if (parser->method) +        direction = "in"; +      else if (parser->signal) +        direction = "out"; +      else +        g_assert_not_reached (); +    } + +  if (strcmp (direction, "in") == 0) +    dir = ARG_IN; +  else if (strcmp (direction, "out") == 0) +    dir = ARG_OUT; +  else +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("\"%s\" attribute on <%s> has value \"in\" or \"out\""), +                   "direction", element_name); +      return FALSE; +    } + +  t = type_from_string (type); +   +  arg = arg_info_new (name, dir, t); +  if (parser->method) +    method_info_add_arg (parser->method, arg); +  else if (parser->signal) +    signal_info_add_arg (parser->signal, arg); +  else +    g_assert_not_reached (); + +  arg_info_unref (arg); + +  parser->arg = arg; +   +  return TRUE; +} +  gboolean  parser_start_element (Parser      *parser,                        const char  *element_name, @@ -85,8 +546,46 @@ parser_start_element (Parser      *parser,                        const char **attribute_values,                        GError     **error)  { -  g_return_val_if_fail (error == NULL || *error == NULL); +  g_return_val_if_fail (error == NULL || *error == NULL, FALSE); +  if (ELEMENT_IS ("node")) +    { +      if (!parse_node (parser, element_name, attribute_names, +                       attribute_values, error)) +        return FALSE; +    } +  else if (ELEMENT_IS ("interface")) +    { +      if (!parse_interface (parser, element_name, attribute_names, +                            attribute_values, error)) +        return FALSE; +    } +  else if (ELEMENT_IS ("method")) +    { +      if (!parse_method (parser, element_name, attribute_names, +                         attribute_values, error)) +        return FALSE; +    } +  else if (ELEMENT_IS ("signal")) +    { +      if (!parse_signal (parser, element_name, attribute_names, +                         attribute_values, error)) +        return FALSE; +    } +  else if (ELEMENT_IS ("arg")) +    { +      if (!parse_arg (parser, element_name, attribute_names, +                      attribute_values, error)) +        return FALSE; +    } +  else +    { +      g_set_error (error, G_MARKUP_ERROR, +                   G_MARKUP_ERROR_PARSE, +                   _("Element <%s> not recognized"), +                   element_name); +    } +      return TRUE;  } @@ -95,8 +594,40 @@ parser_end_element (Parser      *parser,                      const char  *element_name,                      GError     **error)  { -  g_return_val_if_fail (error == NULL || *error == NULL); +  g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + +  if (ELEMENT_IS ("interface")) +    { +      parser->interface = NULL; +    } +  else if (ELEMENT_IS ("method")) +    { +      parser->method = NULL; +    } +  else if (ELEMENT_IS ("signal")) +    { +      parser->signal = NULL; +    } +  else if (ELEMENT_IS ("arg")) +    { +      parser->arg = NULL; +    } +  else if (ELEMENT_IS ("node")) +    { +      NodeInfo *top; +      g_assert (parser->node_stack != NULL); +      top = parser->node_stack->data; + +      parser->node_stack = g_slist_remove (parser->node_stack, +                                           top); + +      if (parser->node_stack == NULL) +        parser->result = top; /* We are done, store the result */       +    } +  else +    g_assert_not_reached (); /* should have had an error on start_element */ +      return TRUE;  } @@ -106,7 +637,7 @@ parser_content (Parser      *parser,                  int          len,                  GError     **error)  { -  g_return_val_if_fail (error == NULL || *error == NULL); +  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);    return TRUE;  } @@ -115,7 +646,13 @@ gboolean  parser_finished (Parser      *parser,                   GError     **error)  { -  g_return_val_if_fail (error == NULL || *error == NULL); +  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);    return TRUE;  } + +NodeInfo* +parser_get_nodes (Parser *parser) +{ +  return parser->result; +} diff --git a/glib/dbus-gparser.h b/glib/dbus-gparser.h index 01339fbf..3e87165b 100644 --- a/glib/dbus-gparser.h +++ b/glib/dbus-gparser.h @@ -25,10 +25,10 @@  #include <dbus/dbus.h>  #include <glib.h> +#include "dbus-gidl.h"  G_BEGIN_DECLS -  typedef struct Parser Parser;  Parser*  parser_new           (void); @@ -52,7 +52,13 @@ gboolean parser_content       (Parser      *parser,  gboolean parser_finished      (Parser      *parser,                                 GError     **error); +Parser* description_load_from_file   (const char  *filename, +                                      GError     **error); +Parser* description_load_from_string (const char  *str, +                                      int          len, +                                      GError     **error); +NodeInfo* parser_get_nodes (Parser *parser);  G_END_DECLS | 
