diff options
author | David Zeuthen <davidz@redhat.com> | 2010-06-16 20:39:57 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-06-16 20:39:57 -0400 |
commit | 5700b0c08cd5c37097af442d784c489e88e24cb5 (patch) | |
tree | e36b23225db5e289d451832304310d78537b4bd8 | |
parent | 4384036f5bb77c02292c7fb6e1091bc5233a1eff (diff) |
Handle returning arrays
-rw-r--r-- | src/gdbusgi.c | 765 | ||||
-rw-r--r-- | src/myfrobnicator.c | 76 | ||||
-rw-r--r-- | src/myfrobnicator.h | 11 | ||||
-rw-r--r-- | src/test.c | 79 |
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__ */ @@ -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 |