summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-06-16 20:39:57 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-06-16 20:39:57 -0400
commit5700b0c08cd5c37097af442d784c489e88e24cb5 (patch)
treee36b23225db5e289d451832304310d78537b4bd8
parent4384036f5bb77c02292c7fb6e1091bc5233a1eff (diff)
Handle returning arrays
-rw-r--r--src/gdbusgi.c765
-rw-r--r--src/myfrobnicator.c76
-rw-r--r--src/myfrobnicator.h11
-rw-r--r--src/test.c79
4 files changed, 662 insertions, 269 deletions
diff --git a/src/gdbusgi.c b/src/gdbusgi.c
index 65b339e..f34270a 100644
--- a/src/gdbusgi.c
+++ b/src/gdbusgi.c
@@ -278,86 +278,232 @@ get_gvariant_type_for_gi_type (GITypeInfo *gi_type,
/* ---------------------------------------------------------------------------------------------------- */
+/* g_error()'s if type is not a scalar type */
+static guint
+get_scalar_element_size (GITypeInfo *type)
+{
+ GITypeTag tag;
+ guint ret;
+
+ ret = 0;
+
+ tag = g_type_info_get_tag (type);
+ switch (tag)
+ {
+ case GI_TYPE_TAG_BOOLEAN:
+ ret = sizeof (gboolean);
+ break;
+
+ case GI_TYPE_TAG_INT8:
+ ret = sizeof (gint8);
+ break;
+
+ case GI_TYPE_TAG_UINT8:
+ ret = sizeof (guint8);
+ break;
+
+ case GI_TYPE_TAG_INT16:
+ ret = sizeof (gint16);
+ break;
+
+ case GI_TYPE_TAG_UINT16:
+ ret = sizeof (guint16);
+ break;
+
+ case GI_TYPE_TAG_INT32:
+ ret = sizeof (gint32);
+ break;
+
+ case GI_TYPE_TAG_UINT32:
+ ret = sizeof (guint32);
+ break;
+
+ case GI_TYPE_TAG_INT64:
+ ret = sizeof (gint64);
+ break;
+
+ case GI_TYPE_TAG_UINT64:
+ ret = sizeof (guint64);
+ break;
+
+ case GI_TYPE_TAG_INT:
+ ret = sizeof (gint);
+ break;
+
+ case GI_TYPE_TAG_UINT:
+ ret = sizeof (guint);
+ break;
+
+ case GI_TYPE_TAG_DOUBLE:
+ ret = sizeof (gdouble);
+ break;
+
+ default:
+ g_error ("Type with tag `%s' is not a scalar type", g_type_tag_to_string (tag));
+ break;
+ }
+
+ return ret;
+}
+
+static guint64
+argument_get_number (GArgument *arg,
+ GITypeInfo *type)
+{
+ guint64 ret;
+
+ g_return_val_if_fail (arg != NULL, 0);
+ g_return_val_if_fail (type != NULL, 0);
+
+ switch (g_type_info_get_tag (type))
+ {
+ case GI_TYPE_TAG_INT8:
+ ret = arg->v_int8;
+ break;
+
+ case GI_TYPE_TAG_UINT8:
+ ret = arg->v_uint8;
+ break;
+
+ case GI_TYPE_TAG_INT16:
+ ret = arg->v_int16;
+ break;
+
+ case GI_TYPE_TAG_UINT16:
+ ret = arg->v_uint16;
+ break;
+
+ case GI_TYPE_TAG_INT32:
+ ret = arg->v_int32;
+ break;
+
+ case GI_TYPE_TAG_UINT32:
+ ret = arg->v_uint32;
+ break;
+
+ case GI_TYPE_TAG_INT64:
+ ret = arg->v_int64;
+ break;
+
+ case GI_TYPE_TAG_UINT64:
+ ret = arg->v_uint64;
+ break;
+
+ case GI_TYPE_TAG_INT:
+ ret = arg->v_int;
+ break;
+
+ case GI_TYPE_TAG_UINT:
+ ret = arg->v_uint;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return ret;
+}
+
+/**
+ * convert_gi_to_gvariant:
+ * @value: The #GArgument to write the converted value to.
+ * @type: The type of @value.
+ * @array_len_value: The #GArgument to read the array length from or %NULL if not an array with length stored elsewhere.
+ * @array_len_type: The type of @array_len_value or %NULL if not an array with length stored elsewhere.
+ * @expected_gvariant_type: The expected type of #GVariant to return or %NULL.
+ *
+ * Converts the value in @value of the type specified by @type into a
+ * #GVariant.
+ *
+ * If @type is an array with the length specified elsewhere, then @array_len_value and @array_len_type must not be
+ * not %NULL.
+ *
+ * Returns: A #GVariant.
+ */
static GVariant *
-convert_gi_to_gvariant (GArgument *gi_value,
- GITypeInfo *gi_type,
- const GVariantType *expected_gvariant_type) /* may be NULL */
+convert_gi_to_gvariant (GArgument *value,
+ GITypeInfo *type,
+ const GVariantType *expected_gvariant_type,
+ GArgument *array_len_value,
+ GITypeInfo *array_len_type)
{
GVariant *ret;
GITypeTag tag;
+ guint n;
- g_return_val_if_fail (gi_value != NULL, NULL);
- g_return_val_if_fail (gi_type != NULL, NULL);
+ g_return_val_if_fail (value != NULL, NULL);
+ g_return_val_if_fail (type != NULL, NULL);
ret = NULL;
- tag = g_type_info_get_tag (gi_type);
+ tag = g_type_info_get_tag (type);
switch (tag)
{
case GI_TYPE_TAG_BOOLEAN:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_BOOLEAN));
- ret = g_variant_new_boolean (gi_value->v_boolean);
+ ret = g_variant_new_boolean (value->v_boolean);
break;
case GI_TYPE_TAG_INT8:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_BYTE));
- ret = g_variant_new_byte (gi_value->v_int8);
+ ret = g_variant_new_byte (value->v_int8);
break;
case GI_TYPE_TAG_UINT8:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_BYTE));
- ret = g_variant_new_byte (gi_value->v_uint8);
+ ret = g_variant_new_byte (value->v_uint8);
break;
case GI_TYPE_TAG_INT16:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_INT16));
- ret = g_variant_new_int16 (gi_value->v_int16);
+ ret = g_variant_new_int16 (value->v_int16);
break;
case GI_TYPE_TAG_UINT16:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_UINT16));
- ret = g_variant_new_uint16 (gi_value->v_uint16);
+ ret = g_variant_new_uint16 (value->v_uint16);
break;
case GI_TYPE_TAG_INT:
case GI_TYPE_TAG_INT32:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_INT32));
- ret = g_variant_new_int32 (gi_value->v_int32);
+ ret = g_variant_new_int32 (value->v_int32);
break;
case GI_TYPE_TAG_UINT:
case GI_TYPE_TAG_UINT32:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_UINT32));
- ret = g_variant_new_uint32 (gi_value->v_uint32);
+ ret = g_variant_new_uint32 (value->v_uint32);
break;
case GI_TYPE_TAG_INT64:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_INT64));
- ret = g_variant_new_int64 (gi_value->v_int64);
+ ret = g_variant_new_int64 (value->v_int64);
break;
case GI_TYPE_TAG_UINT64:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_UINT64));
- ret = g_variant_new_uint64 (gi_value->v_uint64);
+ ret = g_variant_new_uint64 (value->v_uint64);
break;
case GI_TYPE_TAG_DOUBLE:
g_assert (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_DOUBLE));
- ret = g_variant_new_double (gi_value->v_double);
+ ret = g_variant_new_double (value->v_double);
break;
case GI_TYPE_TAG_UTF8:
if (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_STRING))
{
- ret = g_variant_new_string (gi_value->v_string);
+ ret = g_variant_new_string (value->v_string);
}
else if (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_OBJECT_PATH))
{
- ret = g_variant_new_object_path (gi_value->v_string);
+ ret = g_variant_new_object_path (value->v_string);
}
else if (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_SIGNATURE))
{
- ret = g_variant_new_signature (gi_value->v_string);
+ ret = g_variant_new_signature (value->v_string);
}
else
{
@@ -365,6 +511,176 @@ convert_gi_to_gvariant (GArgument *gi_value,
}
break;
+ case GI_TYPE_TAG_ARRAY:
+ {
+ const GVariantType *element_expected_gvariant_type;
+ GITypeInfo *element_type;
+ GITypeTag element_type_tag;
+
+ g_assert (g_variant_type_is_array (expected_gvariant_type));
+
+ element_type = g_type_info_get_param_type (type, 0);
+ element_type_tag = g_type_info_get_tag (element_type);
+ element_expected_gvariant_type = g_variant_type_element (expected_gvariant_type);
+
+ switch (g_type_info_get_array_type (type))
+ {
+ case GI_ARRAY_TYPE_C:
+ if (g_type_info_is_zero_terminated (type))
+ {
+ GVariantBuilder builder;
+ gpointer *p;
+ if (expected_gvariant_type != NULL)
+ g_variant_builder_init (&builder, expected_gvariant_type);
+ else
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+ p = value->v_pointer;
+ while (*p != NULL)
+ {
+ GVariant *element_variant;
+ element_variant = convert_gi_to_gvariant ((GArgument *) p,
+ element_type,
+ element_expected_gvariant_type,
+ NULL,
+ NULL);
+ g_variant_ref_sink (element_variant);
+ g_variant_builder_add_value (&builder, element_variant);
+ g_variant_unref (element_variant);
+ p += 1;
+ }
+ ret = g_variant_builder_end (&builder);
+ }
+ else if (g_type_info_get_array_length (type) != -1)
+ {
+ guint64 array_len;
+
+ g_assert (array_len_value != NULL && array_len_type != NULL);
+ array_len = argument_get_number (array_len_value, array_len_type);
+
+ /* We only support scalar types and strings here */
+ if (g_type_info_get_tag (element_type) == GI_TYPE_TAG_UTF8)
+ {
+ GVariantBuilder builder;
+ if (expected_gvariant_type != NULL)
+ g_variant_builder_init (&builder, expected_gvariant_type);
+ else
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+ for (n = 0; n < array_len; n++)
+ {
+ GArgument *element;
+ GVariant *element_variant;
+ element = (GArgument *) ((gpointer *) value->v_pointer + n);
+ element_variant = convert_gi_to_gvariant (element,
+ element_type,
+ element_expected_gvariant_type,
+ NULL,
+ NULL);
+ g_variant_ref_sink (element_variant);
+ g_variant_builder_add_value (&builder, element_variant);
+ g_variant_unref (element_variant);
+ }
+ ret = g_variant_builder_end (&builder);
+ }
+ else
+ {
+ GVariantBuilder builder;
+ guint element_size;
+ element_size = get_scalar_element_size (element_type);
+ if (expected_gvariant_type != NULL)
+ g_variant_builder_init (&builder, expected_gvariant_type);
+ else
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+ for (n = 0; n < array_len; n++)
+ {
+ GArgument *element;
+ GVariant *element_variant;
+ element = (GArgument *) ((guchar *) value->v_pointer + element_size * n);
+ element_variant = convert_gi_to_gvariant (element,
+ element_type,
+ element_expected_gvariant_type,
+ NULL,
+ NULL);
+ g_variant_ref_sink (element_variant);
+ g_variant_builder_add_value (&builder, element_variant);
+ g_variant_unref (element_variant);
+ }
+ ret = g_variant_builder_end (&builder);
+ }
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+ break;
+
+ case GI_ARRAY_TYPE_BYTE_ARRAY:
+ /* Explicit fallthrough: A GByteArray is really just a GArray */
+ case GI_ARRAY_TYPE_ARRAY:
+ {
+ GVariantBuilder builder;
+ guint element_size;
+ GArray *array;
+
+ array = (GArray *) value->v_pointer;
+
+ element_size = get_scalar_element_size (element_type);
+ g_assert_cmpint (element_size, ==, g_array_get_element_size (array));
+
+ if (expected_gvariant_type != NULL)
+ g_variant_builder_init (&builder, expected_gvariant_type);
+ else
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+ for (n = 0; n < array->len; n++)
+ {
+ GArgument *element;
+ GVariant *element_variant;
+ element = (GArgument *) (array->data + element_size * n);
+ element_variant = convert_gi_to_gvariant (element,
+ element_type,
+ element_expected_gvariant_type,
+ NULL,
+ NULL);
+ g_variant_ref_sink (element_variant);
+ g_variant_builder_add_value (&builder, element_variant);
+ g_variant_unref (element_variant);
+ }
+ ret = g_variant_builder_end (&builder);
+ }
+ break;
+
+ case GI_ARRAY_TYPE_PTR_ARRAY:
+ {
+ GVariantBuilder builder;
+ GPtrArray *ptrarray;
+
+ ptrarray = (GPtrArray *) value->v_pointer;
+
+ if (expected_gvariant_type != NULL)
+ g_variant_builder_init (&builder, expected_gvariant_type);
+ else
+ g_variant_builder_init (&builder, G_VARIANT_TYPE_ARRAY);
+ for (n = 0; n < ptrarray->len; n++)
+ {
+ GArgument *element;
+ GVariant *element_variant;
+ element = (GArgument *) (&ptrarray->pdata[n]);
+ element_variant = convert_gi_to_gvariant (element,
+ element_type,
+ element_expected_gvariant_type,
+ NULL,
+ NULL);
+ g_variant_ref_sink (element_variant);
+ g_variant_builder_add_value (&builder, element_variant);
+ g_variant_unref (element_variant);
+ }
+ ret = g_variant_builder_end (&builder);
+ }
+ break;
+ }
+ g_base_info_unref ((GIBaseInfo *) element_type);
+ }
+ break;
+
default:
g_assert_not_reached ();
break;
@@ -427,75 +743,8 @@ argument_put_number (GArgument *arg,
default:
g_assert_not_reached ();
- }
-}
-
-/* g_error()'s if type is not a scalar type */
-static guint
-get_scalar_element_size (GITypeInfo *type)
-{
- GITypeTag tag;
- guint ret;
-
- ret = 0;
-
- tag = g_type_info_get_tag (type);
- switch (tag)
- {
- case GI_TYPE_TAG_BOOLEAN:
- ret = sizeof (gboolean);
- break;
-
- case GI_TYPE_TAG_INT8:
- ret = sizeof (gint8);
- break;
-
- case GI_TYPE_TAG_UINT8:
- ret = sizeof (guint8);
- break;
-
- case GI_TYPE_TAG_INT16:
- ret = sizeof (gint16);
- break;
-
- case GI_TYPE_TAG_UINT16:
- ret = sizeof (guint16);
- break;
-
- case GI_TYPE_TAG_INT32:
- ret = sizeof (gint32);
- break;
-
- case GI_TYPE_TAG_UINT32:
- ret = sizeof (guint32);
- break;
-
- case GI_TYPE_TAG_INT64:
- ret = sizeof (gint64);
- break;
-
- case GI_TYPE_TAG_UINT64:
- ret = sizeof (guint64);
- break;
-
- case GI_TYPE_TAG_INT:
- ret = sizeof (gint);
- break;
-
- case GI_TYPE_TAG_UINT:
- ret = sizeof (guint);
- break;
-
- case GI_TYPE_TAG_DOUBLE:
- ret = sizeof (gdouble);
- break;
-
- default:
- g_error ("Type with tag `%s' is not a scalar type", g_type_tag_to_string (tag));
break;
}
-
- return ret;
}
/**
@@ -625,13 +874,6 @@ convert_gvariant_to_gi (GVariant *variant,
{
case GI_ARRAY_TYPE_C:
{
-#if 1
- g_print ("fixed_size=%d array_length=%d zero_terminated=%d\n",
- g_type_info_get_array_fixed_size (type),
- g_type_info_get_array_length (type),
- g_type_info_is_zero_terminated (type));
-#endif
-
if (g_type_info_is_zero_terminated (type))
{
gpointer *p;
@@ -656,7 +898,7 @@ convert_gvariant_to_gi (GVariant *variant,
else if (g_type_info_get_array_length (type) != -1)
{
- g_assert (array_len_value != NULL && array_len_type);
+ g_assert (array_len_value != NULL && array_len_type != NULL);
argument_put_number (array_len_value, array_len_type, num_elems);
/* We only support scalar types and strings here */
@@ -802,8 +1044,26 @@ export_data_free (ExportData *data)
g_free (data);
}
+/* ---------------------------------------------------------------------------------------------------- */
+
+typedef struct _ArgData ArgData;
+
typedef struct
{
+ GIFunctionInfo *method;
+ GDBusMethodInfo *dbus_method;
+
+ guint num_in_args; /* number of GIArgInfo where direction is IN or IN_OUT */
+ guint num_out_args; /* number of GIArgInfo where direction is OUT or IN_OUT */
+
+ GPtrArray *args;
+ ArgData *return_value;
+} MethodData;
+
+struct _ArgData
+{
+ GIDirection direction;
+
/* may be NULL for e.g. this/self or if the param is not exported via D-Bus (e.g. array length) */
GDBusArgInfo *dbus_arg_info;
@@ -814,11 +1074,10 @@ typedef struct
GITypeInfo *type_info;
GITransfer transfer;
- /* these are -1 if not set */
+ /* the following indices are -1 if not set */
gint array_len_position;
gint is_array_len_for_position;
- gint inout_in_arg_offset;
-} ArgData;
+};
static ArgData *
arg_data_new (void)
@@ -827,22 +1086,9 @@ arg_data_new (void)
data = g_new0 (ArgData, 1);
data->array_len_position = -1;
data->is_array_len_for_position = -1;
- data->inout_in_arg_offset = -1;
return data;
}
-static ArgData *
-arg_data_dup_without_dbus_arg_info (ArgData *data)
-{
- ArgData *copy;
- copy = g_memdup (data, sizeof (ArgData));
- if (copy->arg_info != NULL)
- g_base_info_ref ((GIBaseInfo *) copy->arg_info);
- if (copy->type_info != NULL)
- g_base_info_ref ((GIBaseInfo *) copy->type_info);
- return copy;
-}
-
static void
arg_data_free (ArgData *data)
{
@@ -855,25 +1101,13 @@ arg_data_free (ArgData *data)
g_free (data);
}
-typedef struct
-{
- GIFunctionInfo *method;
- GDBusMethodInfo *dbus_method;
-
- /* The following ArgData* correspond exactly to what g_function_info_invoke() requires */
- GPtrArray *in_args;
- GPtrArray *out_args;
- ArgData *return_value;
-} MethodData;
-
static void
method_data_free (MethodData *data)
{
g_base_info_unref (data->method);
if (data->dbus_method != NULL)
g_dbus_method_info_unref (data->dbus_method);
- g_ptr_array_unref (data->in_args);
- g_ptr_array_unref (data->out_args);
+ g_ptr_array_unref (data->args);
if (data->return_value != NULL)
arg_data_free (data->return_value);
g_free (data);
@@ -889,23 +1123,22 @@ arg_data_print (ArgData *data)
str = g_string_new (NULL);
g_string_append_printf (str,
- "alp=%2d ialfp=%2d ioiao=%2d ",
+ "alp=%2d ialfp=%2d ",
data->array_len_position,
- data->is_array_len_for_position,
- data->inout_in_arg_offset);
+ data->is_array_len_for_position);
if (data->arg_info == NULL)
- g_string_append (str, "name=(none)");
+ g_string_append (str, "name=-");
else
g_string_append_printf (str, "name=%s", g_base_info_get_name ((GIBaseInfo *) data->arg_info));
if (data->type_info == NULL)
- g_string_append (str, " type=(none)");
+ g_string_append (str, " type=-");
else
g_string_append_printf (str, " type=%s", g_type_tag_to_string (g_type_info_get_tag (data->type_info)));
if (data->dbus_arg_info == NULL)
- g_string_append (str, " sig=(none)");
+ g_string_append (str, " sig=-");
else
g_string_append_printf (str, " sig=%s", data->dbus_arg_info->signature);
@@ -926,28 +1159,40 @@ method_data_print (MethodData *data,
"%*sD-Bus name: %s\n",
indent, "", g_function_info_get_symbol (data->method),
indent, "", data->dbus_method->name);
- for (n = 0; n < data->in_args->len; n++)
- {
- ArgData *a = data->in_args->pdata[n];
- s = arg_data_print (a);
- g_string_append_printf (str,
- "%*s in_arg[%2d]: %s\n",
- indent, "", n, s);
- g_free (s);
- }
- for (n = 0; n < data->out_args->len; n++)
+ for (n = 0; n < data->args->len; n++)
{
- ArgData *a = data->out_args->pdata[n];
- s = arg_data_print (a);
+ ArgData *ad = data->args->pdata[n];
+ const gchar *direction_str;
+
+ direction_str = " in";
+ if (ad->arg_info != NULL)
+ {
+ switch (ad->direction)
+ {
+ case GI_DIRECTION_IN:
+ direction_str = " in";
+ break;
+
+ case GI_DIRECTION_OUT:
+ direction_str = " out";
+ break;
+
+ case GI_DIRECTION_INOUT:
+ direction_str = "inout";
+ break;
+ }
+ }
+
+ s = arg_data_print (ad);
g_string_append_printf (str,
- "%*s out_arg[%2d]: %s\n",
- indent, "", n, s);
+ "%*s arg[%2d]: %s: %s\n",
+ indent, "", n, direction_str, s);
g_free (s);
}
s = arg_data_print (data->return_value);
g_string_append_printf (str,
- "%*s return value: %s\n",
+ "%*s return value: out: %s\n",
indent, "", s);
g_free (s);
@@ -971,64 +1216,53 @@ method_data_dump (MethodData *data,
static void
prepare_args (GVariant *parameters,
- GArgument *in_args,
- GArgument *out_args,
- GArgument *out_arg_values,
+ GArgument **args,
MethodData *data)
{
guint n;
GVariantIter iter;
g_variant_iter_init (&iter, parameters);
- for (n = 0; n < data->in_args->len; n++)
+ for (n = 0; n < data->args->len; n++)
{
ArgData *ad;
GVariant *item;
GArgument *array_len_arg;
GITypeInfo *array_len_arg_type;
- ad = data->in_args->pdata[n];
- if (ad->dbus_arg_info == NULL)
+ ad = data->args->pdata[n];
+ if (!(ad->direction == GI_DIRECTION_IN || ad->direction == GI_DIRECTION_INOUT))
continue;
- item = g_variant_iter_next_value (&iter);
- g_assert (item != NULL);
-
- array_len_arg = NULL;
- array_len_arg_type = NULL;
- if (ad->array_len_position != -1)
+ if (ad->dbus_arg_info != NULL)
{
- array_len_arg = &in_args[ad->array_len_position];
- array_len_arg_type = ((ArgData *) data->in_args->pdata[ad->array_len_position])->type_info;
- }
+ item = g_variant_iter_next_value (&iter);
+ g_assert (item != NULL);
- convert_gvariant_to_gi (item,
- &in_args[n],
- ad->type_info,
- ad->transfer,
- array_len_arg,
- array_len_arg_type);
- }
- g_assert (g_variant_iter_next_value (&iter) == NULL);
-
- for (n = 0; n < data->out_args->len; n++)
- {
- ArgData *ad;
+ array_len_arg = NULL;
+ array_len_arg_type = NULL;
+ if (ad->array_len_position != -1)
+ {
+ array_len_arg = args[ad->array_len_position];
+ array_len_arg_type = ((ArgData *) data->args->pdata[ad->array_len_position])->type_info;
+ }
- ad = data->out_args->pdata[n];
- if (ad->inout_in_arg_offset != -1)
- out_args[n].v_pointer = &in_args[ad->inout_in_arg_offset];
- else
- out_args[n].v_pointer = &out_arg_values[n];
+ convert_gvariant_to_gi (item,
+ args[n],
+ ad->type_info,
+ ad->transfer,
+ array_len_arg,
+ array_len_arg_type);
+ }
}
+ g_assert (g_variant_iter_next_value (&iter) == NULL);
}
/* ---------------------------------------------------------------------------------------------------- */
static GVariant *
process_args (GArgument *return_value,
- GArgument *in_args,
- GArgument *out_args,
+ GArgument **args,
MethodData *data)
{
guint n;
@@ -1036,6 +1270,8 @@ process_args (GArgument *return_value,
GVariant *value;
GVariantType *gvariant_type;
GVariantBuilder builder;
+ GArgument *array_len_arg;
+ GITypeInfo *array_len_arg_type;
g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
@@ -1043,22 +1279,48 @@ process_args (GArgument *return_value,
{
ad = data->return_value;
gvariant_type = g_variant_type_new (ad->dbus_arg_info->signature);
+
+ /* TODO: handle array_len */
+
value = convert_gi_to_gvariant (return_value,
ad->type_info,
- gvariant_type);
+ gvariant_type,
+ NULL,
+ NULL);
+ g_variant_ref_sink (value);
g_variant_builder_add_value (&builder, value);
+ g_variant_unref (value);
g_variant_type_free (gvariant_type);
}
- for (n = 0; n < data->out_args->len; n++)
+ for (n = 0; n < data->args->len; n++)
{
- ad = data->out_args->pdata[n];
- gvariant_type = g_variant_type_new (ad->dbus_arg_info->signature);
- value = convert_gi_to_gvariant ((GArgument *) out_args[n].v_pointer,
- ad->type_info,
- gvariant_type);
- g_variant_builder_add_value (&builder, value);
- g_variant_type_free (gvariant_type);
+ ad = data->args->pdata[n];
+
+ if (!(ad->direction == GI_DIRECTION_OUT || ad->direction == GI_DIRECTION_INOUT))
+ continue;
+
+ if (ad->dbus_arg_info != NULL)
+ {
+ array_len_arg = NULL;
+ array_len_arg_type = NULL;
+ if (ad->array_len_position != -1)
+ {
+ array_len_arg = args[ad->array_len_position];
+ array_len_arg_type = ((ArgData *) data->args->pdata[ad->array_len_position])->type_info;
+ }
+
+ gvariant_type = g_variant_type_new (ad->dbus_arg_info->signature);
+ value = convert_gi_to_gvariant (args[n],
+ ad->type_info,
+ gvariant_type,
+ array_len_arg,
+ array_len_arg_type);
+ g_variant_ref_sink (value);
+ g_variant_builder_add_value (&builder, value);
+ g_variant_unref (value);
+ g_variant_type_free (gvariant_type);
+ }
}
return g_variant_builder_end (&builder);
@@ -1128,8 +1390,7 @@ free_one_arg (GArgument *arg,
static void
free_args (GArgument *return_value,
- GArgument *in_args,
- GArgument *out_args,
+ GArgument **args,
MethodData *data)
{
guint n;
@@ -1142,18 +1403,10 @@ free_args (GArgument *return_value,
}
/* want to skip this/self so start at 1 */
- for (n = 1; n < data->in_args->len; n++)
- {
- ad = data->in_args->pdata[n];
- free_one_arg (&in_args[n], ad->type_info, ad->transfer);
- }
-
- for (n = 0; n < data->out_args->len; n++)
+ for (n = 1; n < data->args->len; n++)
{
- ad = data->out_args->pdata[n];
- /* if inout, it's already been freed in the loop */
- if (ad->inout_in_arg_offset == -1)
- free_one_arg (out_args[n].v_pointer, ad->type_info, ad->transfer);
+ ad = data->args->pdata[n];
+ free_one_arg (args[n], ad->type_info, ad->transfer);
}
}
@@ -1179,30 +1432,60 @@ on_method_call (GDBusConnection *connection,
GArgument *in_args;
GArgument *out_args;
GArgument *out_arg_values;
+ GArgument **args;
gboolean deferred;
gboolean invocation_result;
GArgument return_value = {0};
+ guint n;
+ guint in;
+ guint out;
in_args = NULL;
out_args = NULL;
+ g_print ("##### %s #####\n", method_name);
+
/* The GDBus core guarantees that only methods matching the given
* introspection data is dispatched.
*/
method_data = g_hash_table_lookup (data->dbus_method_name_to_method_data, method_name);
g_assert (method_data != NULL);
- in_args = g_new0 (GArgument, method_data->in_args->len);
- out_args = g_new0 (GArgument, method_data->out_args->len);
- out_arg_values = g_new0 (GArgument, method_data->out_args->len);
+ /* Allocate GArgument vectors */
+ in_args = g_new0 (GArgument, method_data->num_in_args);
+ out_args = g_new0 (GArgument, method_data->num_out_args);
+ out_arg_values = g_new0 (GArgument, method_data->num_out_args);
+
+ /* Collect all in/out/inout GArgument pointers into a array
+ * and initialize all out pointers.
+ */
+ in = out = 0;
+ args = g_new0 (GArgument *, method_data->args->len);
+ for (n = 0; n < method_data->args->len; n++)
+ {
+ ArgData *ad;
+ ad = method_data->args->pdata[n];
+ switch (ad->direction)
+ {
+ case GI_DIRECTION_IN:
+ args[n] = &in_args[in++];
+ break;
+ case GI_DIRECTION_OUT:
+ out_args[out].v_pointer = &out_arg_values[out];
+ args[n] = &out_arg_values[out++];
+ break;
+ case GI_DIRECTION_INOUT:
+ out_args[out++].v_pointer = &in_args[in];
+ args[n] = &in_args[in++];
+ break;
+ }
+ }
/* first is this/self */
in_args[0].v_pointer = data->object;
prepare_args (parameters,
- in_args,
- out_args,
- out_arg_values,
+ args,
method_data);
g_static_private_set (&gobject_invocation, invocation, NULL);
@@ -1212,9 +1495,9 @@ on_method_call (GDBusConnection *connection,
error = NULL;
invocation_result = g_function_info_invoke (method_data->method,
in_args,
- method_data->in_args->len,
+ method_data->num_in_args,
out_args,
- method_data->out_args->len,
+ method_data->num_out_args,
&return_value,
&error);
g_static_private_set (&gobject_invocation, NULL, NULL);
@@ -1231,23 +1514,22 @@ on_method_call (GDBusConnection *connection,
{
GVariant *return_gvariant;
return_gvariant = process_args (&return_value,
- in_args,
- out_args,
+ args,
method_data);
g_dbus_method_invocation_return_value (invocation, return_gvariant);
g_variant_unref (return_gvariant);
}
out:
- if (in_args != NULL)
+ if (args != NULL)
{
free_args (&return_value,
- in_args,
- out_args,
+ args,
method_data);
- g_free (in_args);
- g_free (out_args);
g_free (out_arg_values);
+ g_free (out_args);
+ g_free (in_args);
+ g_free (args);
}
}
@@ -1436,12 +1718,13 @@ get_method_data (GIFunctionInfo *method,
ret = g_new0 (MethodData, 1);
ret->method = g_base_info_ref ((GIBaseInfo *) method);
- ret->in_args = g_ptr_array_new_with_free_func ((GDestroyNotify) arg_data_free);
- ret->out_args = g_ptr_array_new_with_free_func ((GDestroyNotify) arg_data_free);
+ ret->args = g_ptr_array_new_with_free_func ((GDestroyNotify) arg_data_free);
/* this/self */
ad = arg_data_new ();
- g_ptr_array_add (ret->in_args, ad);
+ ad->direction = GI_DIRECTION_IN;
+ g_ptr_array_add (ret->args, ad);
+ ret->num_in_args += 1;
callable = (GICallableInfo *) method;
@@ -1450,8 +1733,10 @@ get_method_data (GIFunctionInfo *method,
/* Handle return value, if any */
return_type = g_callable_info_get_return_type (callable);
ad = arg_data_new ();
+ ad->direction = -1;
ad->type_info = g_base_info_ref ((GIBaseInfo *) return_type);
ad->transfer = g_callable_info_get_caller_owns (callable);
+ ad->array_len_position = g_type_info_get_array_length (return_type);
if (g_type_info_get_tag (return_type) != GI_TYPE_TAG_VOID)
{
GDBusArgInfo *arg_info;
@@ -1489,6 +1774,7 @@ get_method_data (GIFunctionInfo *method,
type = g_arg_info_get_type (arg);
ad = arg_data_new ();
+ ad->direction = g_arg_info_get_direction (arg);
ad->arg_info = g_base_info_ref ((GIBaseInfo *) arg);
ad->type_info = g_arg_info_get_type (arg);
ad->transfer = g_arg_info_get_ownership_transfer (arg);
@@ -1496,6 +1782,7 @@ get_method_data (GIFunctionInfo *method,
/* Now figure out if this arg is a length param for an array */
for (m = 0; m < (guint) g_callable_info_get_n_args (callable) && !not_on_dbus; m++)
{
+ /* TODO: also check return value! */
GIArgInfo *other_arg;
GITypeInfo *other_type;
other_arg = g_callable_info_get_arg (callable, m);
@@ -1539,38 +1826,44 @@ get_method_data (GIFunctionInfo *method,
case GI_DIRECTION_IN:
if (arg_info != NULL)
g_ptr_array_add (in_dbus_args, arg_info);
- g_ptr_array_add (ret->in_args, ad);
+ g_ptr_array_add (ret->args, ad);
+ ret->num_in_args += 1;
break;
+
case GI_DIRECTION_OUT:
if (arg_info != NULL)
g_ptr_array_add (out_dbus_args, arg_info);
- g_ptr_array_add (ret->out_args, ad);
+ g_ptr_array_add (ret->args, ad);
+ ret->num_out_args += 1;
break;
+
case GI_DIRECTION_INOUT:
{
gchar *in_arg_name;
gchar *out_arg_name;
+ GDBusArgInfo *modified;
- in_arg_name = g_strdup_printf ("in_%s", arg_info->name);
- out_arg_name = g_strdup_printf ("out_%s", arg_info->name);
+ g_ptr_array_add (ret->args, ad);
+ ret->num_in_args += 1;
+ ret->num_out_args += 1;
- g_free (arg_info->name);
- arg_info->name = in_arg_name;
- if (arg_info != NULL)
- g_ptr_array_add (in_dbus_args, arg_info);
- g_ptr_array_add (ret->in_args, ad);
+ /* Use modified GDBusArgInfo objects for the actual
+ * introspection where the parameter name has in_ and out_
+ * prefixed for each parameter.
+ */
- ad = arg_data_dup_without_dbus_arg_info (ad);
- ad->dbus_arg_info = get_arg_info (callable, arg, NULL);
- g_assert (ad->dbus_arg_info != NULL);
- g_free (ad->dbus_arg_info->name);
- ad->dbus_arg_info->name = out_arg_name;
- if (arg_info != NULL)
- g_ptr_array_add (out_dbus_args, ad->dbus_arg_info);
+ in_arg_name = g_strdup_printf ("in_%s", arg_info->name);
+ out_arg_name = g_strdup_printf ("out_%s", arg_info->name);
- ad->inout_in_arg_offset = ret->in_args->len - 1;
+ modified = get_arg_info (callable, arg, NULL);
+ g_free (modified->name);
+ modified->name = out_arg_name;
+ g_ptr_array_add (out_dbus_args, modified);
- g_ptr_array_add (ret->out_args, ad);
+ modified = get_arg_info (callable, arg, NULL);
+ g_free (modified->name);
+ modified->name = in_arg_name;
+ g_ptr_array_add (in_dbus_args, modified);
}
break;
}
diff --git a/src/myfrobnicator.c b/src/myfrobnicator.c
index 0ed7065..49c0cfd 100644
--- a/src/myfrobnicator.c
+++ b/src/myfrobnicator.c
@@ -286,7 +286,7 @@ my_frobnicator_poke_path (MyFrobnicator *frobnicator,
* @garray_ad: (element-type gdouble):
* @gptrarray_as: (element-type utf8):
* @carray_as_nzt_len:
- * @carray_as_nzt: : (element-type utf8) (array length=carray_as_nzt_len):
+ * @carray_as_nzt: (element-type utf8) (array length=carray_as_nzt_len):
*
* Returns: The sum of all elements.
*
@@ -332,3 +332,77 @@ my_frobnicator_test_arrays (MyFrobnicator *frobnicator,
return ret;
}
+
+/**
+ * my_frobnicator_return_arrays:
+ * @frobnicator:
+ * @out_garray_ai: (out) (element-type gint):
+ * @out_garray_ad: (out)(element-type gdouble):
+ * @out_gptrarray_as: (out) (element-type utf8):
+ * @out_gbytearray_ay: (out) (element-type guint8):
+ * @out_carray_ai: (out) (array length=out_carray_ai_len):
+ * @out_carray_ai_len:
+ * @out_carray_as_nzt_len:
+ * @out_carray_as_nzt: (out) (element-type utf8) (array length=out_carray_as_nzt_len):
+ * @out_carray_as: (out) (array) (element-type utf8):
+ *
+ * Attributes: (gdbus.method ReturnArrays)
+ */
+void
+my_frobnicator_return_arrays (MyFrobnicator *frobnicator,
+ GArray **out_garray_ai,
+ GArray **out_garray_ad,
+ GPtrArray **out_gptrarray_as,
+ GByteArray **out_gbytearray_ay,
+ gint **out_carray_ai,
+ guint *out_carray_ai_len,
+ guint *out_carray_as_nzt_len,
+ gchar ***out_carray_as_nzt,
+ gchar ***out_carray_as)
+{
+ gint *ai;
+ gchar **as;
+
+ *out_garray_ai = g_array_new (FALSE, FALSE, sizeof (gint));
+ g_array_set_size (*out_garray_ai, 3);
+ ((gint *) (*out_garray_ai)->data)[0] = 10000;
+ ((gint *) (*out_garray_ai)->data)[1] = 20000;
+ ((gint *) (*out_garray_ai)->data)[2] = 30000;
+
+ *out_garray_ad = g_array_new (FALSE, FALSE, sizeof (gdouble));
+ g_array_set_size (*out_garray_ad, 3);
+ ((gdouble *) (*out_garray_ad)->data)[0] = 1000.0;
+ ((gdouble *) (*out_garray_ad)->data)[1] = 2000.0;
+ ((gdouble *) (*out_garray_ad)->data)[2] = 3000.0;
+
+ *out_gptrarray_as = g_ptr_array_new ();
+ g_ptr_array_add (*out_gptrarray_as, "100");
+ g_ptr_array_add (*out_gptrarray_as, "200");
+ g_ptr_array_add (*out_gptrarray_as, "300");
+
+ *out_gbytearray_ay = g_byte_array_new ();
+ g_byte_array_set_size (*out_gbytearray_ay, 3);
+ (*out_gbytearray_ay)->data[0] = 10;
+ (*out_gbytearray_ay)->data[1] = 20;
+ (*out_gbytearray_ay)->data[2] = 30;
+
+ ai = g_new0 (gint, 3);
+ ai[0] = 1;
+ ai[1] = 2;
+ ai[2] = 3;
+ *out_carray_ai = ai;
+ *out_carray_ai_len = 3;
+
+ as = g_new0 (gchar *, 3);
+ as[0] = g_strdup ("0.1");
+ as[1] = g_strdup ("0.2");
+ as[2] = g_strdup ("0.3");
+ *out_carray_as_nzt = as;
+ *out_carray_as_nzt_len = 3;
+
+ as = g_new0 (gchar *, 4);
+ as[0] = g_strdup ("0.01");
+ as[1] = g_strdup ("0.02");
+ as[2] = g_strdup ("0.03");
+ *out_carray_as = as;
+}
diff --git a/src/myfrobnicator.h b/src/myfrobnicator.h
index f7bb72c..ea9ab42 100644
--- a/src/myfrobnicator.h
+++ b/src/myfrobnicator.h
@@ -117,6 +117,17 @@ gdouble my_frobnicator_test_arrays (MyFrobnicator *frobnicator,
guint carray_as_nzt_len,
const gchar *const *carray_as_nzt);
+void my_frobnicator_return_arrays (MyFrobnicator *frobnicator,
+ GArray **out_garray_ai,
+ GArray **out_garray_ad,
+ GPtrArray **out_gptrarray_as,
+ GByteArray **out_gbytearray_ay,
+ gint **out_carray_ai,
+ guint *out_carray_ai_len,
+ guint *out_carray_as_nzt_len,
+ gchar ***out_carray_as_nzt,
+ gchar ***out_carray_as);
+
G_END_DECLS
#endif /* __MY_FROBNICATOR_H__ */
diff --git a/src/test.c b/src/test.c
index 3ac77e9..5e0f80a 100644
--- a/src/test.c
+++ b/src/test.c
@@ -53,37 +53,6 @@ on_bus_acquired (GDBusConnection *connection,
}
static void
-run_array_test (GDBusConnection *connection)
-{
- GError *error;
- GVariant *ret;
- gdouble d;
-
- error = NULL;
- ret = g_dbus_connection_call_sync (connection,
- "org.My.Service",
- "/org/My/Frobnicator",
- "org.MyProject.Frobnicator",
- "TestArrays",
- g_variant_new_parsed ("([1000, 2000, 3000], "
- " ['100', '200', '300'], "
- " [@y 10, 20, 30], "
- " [1, 2, 3], "
- " [0.1, 0.2, 0.3], "
- " ['0.01', '0.02', '0.03'], "
- " ['0.001', '0.002', '0.003'])"),
- G_VARIANT_TYPE ("(d)"),
- G_DBUS_CALL_FLAGS_NONE,
- -1,
- NULL, /* GCancellable */
- &error);
- g_assert_no_error (error);
- g_variant_get (ret, "(d)", &d);
- g_assert_cmpfloat (fabs (d - 6666.666), <, 1e-10);
- g_variant_unref (ret);
-}
-
-static void
run_test (GDBusConnection *connection)
{
GError *error;
@@ -91,6 +60,8 @@ run_test (GDBusConnection *connection)
gchar *s;
gchar *s2;
guint n;
+ gdouble d;
+ GVariant *other;
error = NULL;
ret = g_dbus_connection_call_sync (connection,
@@ -278,8 +249,52 @@ run_test (GDBusConnection *connection)
}
g_variant_unref (ret);
- run_array_test (connection);
+ error = NULL;
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "TestArrays",
+ g_variant_new_parsed ("([1000, 2000, 3000], "
+ " ['100', '200', '300'], "
+ " [@y 10, 20, 30], "
+ " [1, 2, 3], "
+ " [0.1, 0.2, 0.3], "
+ " ['0.01', '0.02', '0.03'], "
+ " ['0.001', '0.002', '0.003'])"),
+ G_VARIANT_TYPE ("(d)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ g_variant_get (ret, "(d)", &d);
+ g_assert_cmpfloat (fabs (d - 6666.666), <, 1e-10);
+ g_variant_unref (ret);
+ error = NULL;
+ ret = g_dbus_connection_call_sync (connection,
+ "org.My.Service",
+ "/org/My/Frobnicator",
+ "org.MyProject.Frobnicator",
+ "ReturnArrays",
+ NULL,
+ G_VARIANT_TYPE ("(aiadasayaiasas)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, /* GCancellable */
+ &error);
+ g_assert_no_error (error);
+ other = g_variant_new_parsed ("([10000, 20000, 30000], "
+ " [1000.0, 2000.0, 3000.0], "
+ " ['100', '200', '300'], "
+ " [byte 10, 20, 30], "
+ " [1, 2, 3], "
+ " ['0.1', '0.2', '0.3'], "
+ " ['0.01', '0.02', '0.03'])");
+ g_assert (g_variant_equal (ret, other));
+ g_variant_unref (ret);
+ g_variant_unref (other);
}
static gpointer