summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-09-03 02:08:25 +0000
committerHavoc Pennington <hp@redhat.com>2003-09-03 02:08:25 +0000
commitd021cfae6695f0f44102edf758abfc42e2f3c093 (patch)
tree77e95134b676c65557962d50a4eab125a40e6d00
parent7b4ac5de11d90e9f7048f057d70d3da5104388b6 (diff)
downloaddbus-d021cfae6695f0f44102edf758abfc42e2f3c093.tar.gz
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--ChangeLog9
-rw-r--r--configure.in9
-rw-r--r--dbus/dbus-marshal.c4
-rw-r--r--dbus/dbus-protocol.h23
-rw-r--r--glib/Makefile.am6
-rw-r--r--glib/dbus-gidl.c90
-rw-r--r--glib/dbus-gidl.h10
-rw-r--r--glib/dbus-glib.h26
-rw-r--r--glib/dbus-gloader-expat.c254
-rw-r--r--glib/dbus-gobject.c780
-rw-r--r--glib/dbus-gparser.c549
-rw-r--r--glib/dbus-gparser.h8
12 files changed, 1740 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index f57c964a..d9557bed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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