diff options
author | David Zeuthen <davidz@redhat.com> | 2010-06-16 13:53:36 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-06-16 13:53:36 -0400 |
commit | ca054efa1b317a219b2b83652c16e6017b789f30 (patch) | |
tree | e27d2d0f5506933be9cd81694905549a25c0bdb3 | |
parent | 917e0632cb4e8a4508112075b48a608ac36f8c33 (diff) |
Updates
-rw-r--r-- | src/gdbusgi.c | 1482 | ||||
-rw-r--r-- | src/myfrobnicator.c | 54 | ||||
-rw-r--r-- | src/myfrobnicator.h | 8 | ||||
-rw-r--r-- | src/test.c | 33 |
4 files changed, 1124 insertions, 453 deletions
diff --git a/src/gdbusgi.c b/src/gdbusgi.c index 1578d6d..138e00d 100644 --- a/src/gdbusgi.c +++ b/src/gdbusgi.c @@ -23,6 +23,632 @@ #include <girepository.h> +/* ---------------------------------------------------------------------------------------------------- */ + +static GVariantType * +get_gvariant_type_for_gi_type (GITypeInfo *gi_type, + const GVariantType *requested_gvariant_type, /* may be NULL */ + GError **error) +{ + GITypeTag tag; + GVariantType *gvariant_type; + + g_return_val_if_fail (gi_type != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + gvariant_type = NULL; + + tag = g_type_info_get_tag (gi_type); + switch (tag) + { + case GI_TYPE_TAG_BOOLEAN: + gvariant_type = g_variant_type_new ("b"); + break; + + case GI_TYPE_TAG_INT8: + gvariant_type = g_variant_type_new ("y"); + break; + + case GI_TYPE_TAG_UINT8: + gvariant_type = g_variant_type_new ("y"); + break; + + case GI_TYPE_TAG_INT16: + gvariant_type = g_variant_type_new ("n"); + break; + + case GI_TYPE_TAG_UINT16: + gvariant_type = g_variant_type_new ("q"); + break; + + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_INT32: + gvariant_type = g_variant_type_new ("i"); + break; + + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_UINT32: + gvariant_type = g_variant_type_new ("u"); + break; + + case GI_TYPE_TAG_INT64: + gvariant_type = g_variant_type_new ("x"); + break; + + case GI_TYPE_TAG_UINT64: + gvariant_type = g_variant_type_new ("t"); + break; + + case GI_TYPE_TAG_DOUBLE: + gvariant_type = g_variant_type_new ("d"); + break; + + case GI_TYPE_TAG_UTF8: + if (requested_gvariant_type != NULL && + (g_variant_type_equal (requested_gvariant_type, G_VARIANT_TYPE_STRING) || + g_variant_type_equal (requested_gvariant_type, G_VARIANT_TYPE_OBJECT_PATH) || + g_variant_type_equal (requested_gvariant_type, G_VARIANT_TYPE_SIGNATURE))) + gvariant_type = g_variant_type_copy (requested_gvariant_type); + else + gvariant_type = g_variant_type_new ("s"); + break; + + case GI_TYPE_TAG_ARRAY: + { + const GVariantType *element_requested_gvariant_type; + GITypeInfo *element_type; + GVariantType *element_gvariant_type; + GITypeTag element_type_tag; + + element_requested_gvariant_type = NULL; + if (requested_gvariant_type != NULL) + { + if (!g_variant_type_is_array (requested_gvariant_type)) + { + gchar *s; + s = g_variant_type_dup_string (requested_gvariant_type); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Type tag GI_TYPE_ARRAY requires an signature starting with `a' but the " + "requested signature is `%s'", + s); + g_free (s); + goto out; + } + element_requested_gvariant_type = g_variant_type_element (requested_gvariant_type); + } + + element_type = g_type_info_get_param_type (gi_type, 0); + element_type_tag = g_type_info_get_tag (element_type); + element_gvariant_type = get_gvariant_type_for_gi_type (element_type, + element_requested_gvariant_type, + error); + g_base_info_unref ((GIBaseInfo *) element_type); + if (element_gvariant_type == NULL) + goto out; + + switch (g_type_info_get_array_type (gi_type)) + { + case GI_ARRAY_TYPE_C: + switch (element_type_tag) + { + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_UTF8: + /* ^^^ Only these types are OK */ + + /* However, we only support zero-terminated for strings */ + if (element_type_tag != GI_TYPE_TAG_UTF8 && g_type_info_is_zero_terminated (gi_type)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Element type `%s' in C array can't be used with zero-terminated", + g_type_tag_to_string (element_type_tag)); + goto out; + } + break; + + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Unsupported element type `%s' in C array", + g_type_tag_to_string (element_type_tag)); + goto out; + } + + break; + + case GI_ARRAY_TYPE_ARRAY: + switch (element_type_tag) + { + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_DOUBLE: + /* ^^^ Only these types are OK */ + break; + + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Unsupported element type `%s' in GArray array (only scalar types are supported)", + g_type_tag_to_string (element_type_tag)); + goto out; + } + break; + + case GI_ARRAY_TYPE_PTR_ARRAY: + switch (element_type_tag) + { + case GI_TYPE_TAG_UTF8: + /* ^^^ Only this type is OK */ + break; + + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Unsupported element type `%s' in GPtrArray array", + g_type_tag_to_string (element_type_tag)); + goto out; + } + break; + + case GI_ARRAY_TYPE_BYTE_ARRAY: + switch (element_type_tag) + { + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + /* ^^^ Only these types are OK */ + break; + + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Unsupported element type `%s' in GByteArray array", + g_type_tag_to_string (element_type_tag)); + goto out; + } + break; + break; + } + gvariant_type = g_variant_type_new_array (element_gvariant_type); + g_variant_type_free (element_gvariant_type); + } + break; + + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Type tag `%s' not supported", + g_type_tag_to_string (tag)); + goto out; + } + + if (gvariant_type != NULL) + { + if (requested_gvariant_type != NULL && !g_variant_type_equal (gvariant_type, requested_gvariant_type)) + { + gchar *s; + gchar *s2; + s = g_variant_type_dup_string (gvariant_type); + s2 = g_variant_type_dup_string (requested_gvariant_type); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Type tag `%s' defaults to D-Bus signature `%s' which is incompatible with requested signature `%s'", + g_type_tag_to_string (tag), + s, + s2); + g_free (s); + g_free (s2); + g_variant_type_free (gvariant_type); + gvariant_type = NULL; + goto out; + } + } + + out: + return gvariant_type; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static GVariant * +convert_gi_to_gvariant (GArgument *gi_value, + GITypeInfo *gi_type, + const GVariantType *expected_gvariant_type) /* may be NULL */ +{ + GVariant *ret; + GITypeTag tag; + + g_return_val_if_fail (gi_value != NULL, NULL); + g_return_val_if_fail (gi_type != NULL, NULL); + + ret = NULL; + tag = g_type_info_get_tag (gi_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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + 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); + } + else if (g_variant_type_equal (expected_gvariant_type, G_VARIANT_TYPE_OBJECT_PATH)) + { + ret = g_variant_new_object_path (gi_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); + } + else + { + g_assert_not_reached (); + } + break; + + default: + g_assert_not_reached (); + break; + } + + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/* 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 void +convert_gvariant_to_gi (GVariant *variant, + GArgument *out_gi_value, + GITypeInfo *gi_type, + GITransfer transfer) +{ + GITypeTag tag; + const GVariantType *gvariant_type; + + g_return_if_fail (variant != NULL); + g_return_if_fail (out_gi_value != NULL); + g_return_if_fail (gi_type != NULL); + + gvariant_type = g_variant_get_type (variant); + tag = g_type_info_get_tag (gi_type); + + switch (tag) + { + case GI_TYPE_TAG_BOOLEAN: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_BOOLEAN)); + out_gi_value->v_boolean = g_variant_get_boolean (variant); + break; + + case GI_TYPE_TAG_INT8: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_BYTE)); + out_gi_value->v_int8 = g_variant_get_byte (variant); + break; + + case GI_TYPE_TAG_UINT8: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_BYTE)); + out_gi_value->v_uint8 = g_variant_get_byte (variant); + break; + + case GI_TYPE_TAG_INT16: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_INT16)); + out_gi_value->v_int16 = g_variant_get_int16 (variant); + break; + + case GI_TYPE_TAG_UINT16: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_UINT16)); + out_gi_value->v_uint16 = g_variant_get_uint16 (variant); + break; + + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_INT32: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_INT32)); + out_gi_value->v_int32 = g_variant_get_int32 (variant); + break; + + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_UINT32: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_UINT32)); + out_gi_value->v_uint32 = g_variant_get_uint32 (variant); + break; + + case GI_TYPE_TAG_INT64: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_INT64)); + out_gi_value->v_int64 = g_variant_get_int64 (variant); + break; + + case GI_TYPE_TAG_UINT64: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_UINT64)); + out_gi_value->v_uint64 = g_variant_get_uint64 (variant); + break; + + case GI_TYPE_TAG_DOUBLE: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_DOUBLE)); + out_gi_value->v_double = g_variant_get_double (variant); + break; + + case GI_TYPE_TAG_UTF8: + g_assert (g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_STRING) || + g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_OBJECT_PATH) || + g_variant_type_equal (gvariant_type, G_VARIANT_TYPE_SIGNATURE)); + switch (transfer) + { + case GI_TRANSFER_NOTHING: + out_gi_value->v_string = (gchar *) g_variant_get_string (variant, NULL); + break; + case GI_TRANSFER_CONTAINER: + g_assert_not_reached (); + break; + case GI_TRANSFER_EVERYTHING: + out_gi_value->v_string = g_variant_dup_string (variant, NULL); + break; + } + break; + + case GI_TYPE_TAG_ARRAY: + { + GITypeInfo *element_type; + GITransfer element_transfer; + GVariantIter iter; + guint num_elems; + guint n; + + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_ARRAY)); + + element_type = g_type_info_get_param_type (gi_type, 0); + + element_transfer = GI_TRANSFER_NOTHING; + if (transfer == GI_TRANSFER_EVERYTHING) + element_transfer = GI_TRANSFER_EVERYTHING; + + num_elems = g_variant_n_children (variant); + + switch (g_type_info_get_array_type (gi_type)) + { + case GI_ARRAY_TYPE_C: + { +#if 0 + g_print ("fixed_size=%d array_length=%d zero_terminated=%d\n", + g_type_info_get_array_fixed_size (gi_type), + g_type_info_get_array_length (gi_type), + g_type_info_is_zero_terminated (gi_type)); +#endif + + if (g_type_info_is_zero_terminated (gi_type)) + { + gpointer *p; + p = g_new0 (gpointer, num_elems + 1); + g_variant_iter_init (&iter, variant); + for (n = 0; n < num_elems; n++) + { + GArgument a = {0}; + GVariant *item; + item = g_variant_iter_next_value (&iter); + g_assert (item != NULL); + convert_gvariant_to_gi (item, + &a, + element_type, + element_transfer); + p[n] = a.v_pointer; + } + out_gi_value->v_pointer = p; + } + 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: + { + GArray *p; + p = g_array_sized_new (FALSE, /* zero_terminated */ + FALSE, /* clear_ */ + get_scalar_element_size (element_type), + num_elems); + g_variant_iter_init (&iter, variant); + for (n = 0; n < num_elems; n++) + { + GArgument a = {0}; + GVariant *item; + + item = g_variant_iter_next_value (&iter); + g_assert (item != NULL); + convert_gvariant_to_gi (item, + &a, + element_type, + element_transfer); + g_array_append_vals (p, &a, 1); + } + out_gi_value->v_pointer = p; + } + break; + + case GI_ARRAY_TYPE_PTR_ARRAY: + { + GPtrArray *p; + p = g_ptr_array_sized_new (num_elems); + g_variant_iter_init (&iter, variant); + for (n = 0; n < num_elems; n++) + { + GArgument a = {0}; + GVariant *item; + + item = g_variant_iter_next_value (&iter); + g_assert (item != NULL); + convert_gvariant_to_gi (item, + &a, + element_type, + element_transfer); + g_ptr_array_add (p, a.v_pointer); + } + out_gi_value->v_pointer = p; + } + break; + } + g_base_info_unref ((GIBaseInfo *) element_type); + } + break; + + default: + g_error ("Don't know how to convert GVariant with type-string `%s' to type tag `%s'", + g_variant_get_type_string (variant), + g_type_tag_to_string (tag)); + break; + } +} + +/* ---------------------------------------------------------------------------------------------------- */ + typedef struct { GObject *object; @@ -48,298 +674,252 @@ export_data_free (ExportData *data) typedef struct { + /* 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; + + /* may be NULL for self/this or for the return value */ + GIArgInfo *arg_info; + + /* is NULL only for this/self */ + GITypeInfo *type_info; + GITransfer transfer; + + /* these 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) +{ + ArgData *data; + 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) +{ + if (data->dbus_arg_info != NULL) + g_dbus_arg_info_unref (data->dbus_arg_info); + if (data->arg_info != NULL) + g_base_info_unref ((GIBaseInfo *) data->arg_info); + if (data->type_info != NULL) + g_base_info_unref ((GIBaseInfo *) data->type_info); + g_free (data); +} + +typedef struct +{ GIFunctionInfo *method; GDBusMethodInfo *dbus_method; - guint num_gi_in_args; - guint num_gi_out_args; + + /* 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); - g_dbus_method_info_unref (data->dbus_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); + if (data->return_value != NULL) + arg_data_free (data->return_value); g_free (data); } /* ---------------------------------------------------------------------------------------------------- */ -static void -set_in_arg (GVariant *value, - GArgument *arg_to_set, - GIArgInfo *arg_info) +static gchar * +arg_data_print (ArgData *data) { - const GVariantType *variant_type; - - variant_type = g_variant_get_type (value); - - if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN)) - arg_to_set->v_boolean = g_variant_get_boolean (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE)) - arg_to_set->v_int8 = g_variant_get_byte (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16)) - arg_to_set->v_int16 = g_variant_get_int16 (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16)) - arg_to_set->v_uint16 = g_variant_get_uint16 (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32)) - arg_to_set->v_int32 = g_variant_get_int32 (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32)) - arg_to_set->v_uint32 = g_variant_get_uint32 (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64)) - arg_to_set->v_int64 = g_variant_get_int64 (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64)) - arg_to_set->v_uint64 = g_variant_get_uint64 (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE)) - arg_to_set->v_double = g_variant_get_double (value); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING) || - g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH) || - g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE)) - { - switch (g_arg_info_get_ownership_transfer (arg_info)) - { - case GI_TRANSFER_NOTHING: - arg_to_set->v_string = (gchar *) g_variant_get_string (value, NULL); - break; - case GI_TRANSFER_CONTAINER: - g_assert_not_reached (); - break; - case GI_TRANSFER_EVERYTHING: - arg_to_set->v_string = g_variant_dup_string (value, NULL); - break; - } - } - else - { - g_error ("Don't know how to set GVariant with type-string %s on a GArgument", - g_variant_get_type_string (value)); - } -} + GString *str; + str = g_string_new (NULL); -static void -prepare_in_args (GVariant *parameters, - GArgument *in_args, - guint num_in_args, - GIFunctionInfo *method) -{ - GVariantIter iter; - GICallableInfo *callable; - guint count_in_args; - guint count_out_args; - guint n; + g_string_append_printf (str, + "alp=%02d ialfp=%02d ioiao=%02d ", + data->array_len_position, + data->is_array_len_for_position, + data->inout_in_arg_offset); - g_assert_cmpint (g_variant_n_children (parameters), ==, num_in_args); - - callable = (GICallableInfo *) method; + if (data->arg_info == NULL) + g_string_append (str, "name=(none)"); + else + g_string_append_printf (str, "name=%s", g_base_info_get_name ((GIBaseInfo *) data->arg_info)); - count_in_args = 0; - count_out_args = 0; - g_variant_iter_init (&iter, parameters); - for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++) - { - GArgument *arg_to_set; - GIArgInfo *arg; - GIDirection direction; + if (data->type_info == NULL) + g_string_append (str, " type=(none)"); + else + g_string_append_printf (str, " type=%s", g_type_tag_to_string (g_type_info_get_tag (data->type_info))); - arg = g_callable_info_get_arg (callable, n); - direction = g_arg_info_get_direction (arg); - arg_to_set = NULL; - switch (direction) - { - case GI_DIRECTION_IN: - arg_to_set = &in_args[count_in_args++]; - break; + if (data->dbus_arg_info == NULL) + g_string_append (str, " sig=(none)"); + else + g_string_append_printf (str, " sig=%s", data->dbus_arg_info->signature); - case GI_DIRECTION_OUT: - /* do nothing */ - count_out_args++; - break; + return g_string_free (str, FALSE); +} - case GI_DIRECTION_INOUT: - count_out_args++; - arg_to_set = &in_args[count_in_args++]; - break; - } +static gchar * +method_data_print (MethodData *data, + guint indent) +{ + GString *str; + guint n; + gchar *s; + + str = g_string_new (NULL); + g_string_append_printf (str, + "%*sSymbol: %s\n" + "%*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[%02d]: %s\n", + indent, "", n, s); + g_free (s); + } + for (n = 0; n < data->out_args->len; n++) + { + ArgData *a = data->out_args->pdata[n]; + s = arg_data_print (a); + g_string_append_printf (str, + "%*s out_arg[%02d]: %s\n", + indent, "", n, s); + g_free (s); + } - if (arg_to_set != NULL) - { - GVariant *item; + s = arg_data_print (data->return_value); + g_string_append_printf (str, + "%*s return value: %s\n", + indent, "", s); + g_free (s); - item = g_variant_iter_next_value (&iter); - g_assert (item != NULL); - set_in_arg (item, arg_to_set, arg); - } - } - g_assert_cmpint (count_in_args, ==, num_in_args); + return g_string_free (str, FALSE); } -/* ---------------------------------------------------------------------------------------------------- */ - static void -add_out_arg (GVariantBuilder *builder, - GITypeInfo *type, - GArgument *value, - GDBusArgInfo *arg_info) +method_data_dump (MethodData *data, + guint indent) { - const GVariantType *variant_type; - GVariant *variant; - - variant_type = G_VARIANT_TYPE (arg_info->signature); - - if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BOOLEAN)) - variant = g_variant_new_boolean (value->v_boolean); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_BYTE)) - variant = g_variant_new_byte (value->v_uint8); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT16)) - variant = g_variant_new_int16 (value->v_int16); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT16)) - variant = g_variant_new_uint16 (value->v_uint16); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32)) - variant = g_variant_new_int32 (value->v_int32); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT32)) - variant = g_variant_new_uint32 (value->v_uint32); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64)) - variant = g_variant_new_int64 (value->v_int64); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_UINT64)) - variant = g_variant_new_uint64 (value->v_uint64); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_DOUBLE)) - variant = g_variant_new_double (value->v_double); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_STRING)) - variant = g_variant_new_string (value->v_string); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_OBJECT_PATH)) - variant = g_variant_new_object_path (value->v_string); - else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_SIGNATURE)) - variant = g_variant_new_signature (value->v_string); - else - g_assert_not_reached (); - - g_variant_builder_add_value (builder, variant); + gchar *s; + s = method_data_print (data, indent); + g_print ("------------------------------------------------------------------------\n" + "%s" + "------------------------------------------------------------------------\n", + s); + g_free (s); } +/* ---------------------------------------------------------------------------------------------------- */ + static void -prepare_out_args (GArgument *return_value, - GArgument *args, - GArgument *arg_values, - guint num_args, - GIFunctionInfo *method, - GDBusMethodInfo *dbus_method) +prepare_args (GVariant *parameters, + GArgument *in_args, + GArgument *out_args, + GArgument *out_arg_values, + MethodData *data) { - GICallableInfo *callable; guint n; - guint count_out_args; - - callable = (GICallableInfo *) method; + GVariantIter iter; - count_out_args = 0; - for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++) + g_variant_iter_init (&iter, parameters); + for (n = 0; n < data->in_args->len; n++) { - GIArgInfo *arg; - GIDirection direction; + ArgData *ad; + GVariant *item; - arg = g_callable_info_get_arg (callable, n); - direction = g_arg_info_get_direction (arg); + ad = data->in_args->pdata[n]; + if (ad->dbus_arg_info == NULL) + continue; - switch (direction) - { - case GI_DIRECTION_IN: - /* do nothing */ - break; + item = g_variant_iter_next_value (&iter); + g_assert (item != NULL); - case GI_DIRECTION_OUT: - args[count_out_args].v_pointer = &arg_values[count_out_args]; - count_out_args++; - break; + convert_gvariant_to_gi (item, + &in_args[n], + ad->type_info, + ad->transfer); + } + g_assert (g_variant_iter_next_value (&iter) == NULL); - case GI_DIRECTION_INOUT: - /* won't be used but needs to be present */ - args[count_out_args].v_pointer = NULL; - count_out_args++; - break; - } - g_base_info_unref ((GIBaseInfo *) arg); + for (n = 0; n < data->out_args->len; n++) + { + ArgData *ad; + + 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]; } - g_assert_cmpint (num_args, ==, count_out_args); } +/* ---------------------------------------------------------------------------------------------------- */ + static GVariant * -process_out_args (GArgument *return_value, - GArgument *in_args, - GArgument *args, - guint num_args, - GIFunctionInfo *method, - GDBusMethodInfo *dbus_method) +process_args (GArgument *return_value, + GArgument *in_args, + GArgument *out_args, + MethodData *data) { - GVariant *ret; - GVariantBuilder builder; - GICallableInfo *callable; - GITypeInfo *return_type; - guint dbus_arg_num; guint n; - guint count_in_args; - guint count_out_args; - - callable = (GICallableInfo *) method; + ArgData *ad; + GVariant *value; + GVariantType *gvariant_type; + GVariantBuilder builder; g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); - dbus_arg_num = 0; - return_type = g_callable_info_get_return_type (callable); - if (g_type_info_get_tag (return_type) != GI_TYPE_TAG_VOID) + if (g_type_info_get_tag (data->return_value->type_info) != GI_TYPE_TAG_VOID) { - add_out_arg (&builder, - return_type, - return_value, - dbus_method->out_args[dbus_arg_num++]); + ad = data->return_value; + gvariant_type = g_variant_type_new (ad->dbus_arg_info->signature); + value = convert_gi_to_gvariant (return_value, + ad->type_info, + gvariant_type); + g_variant_builder_add_value (&builder, value); + g_variant_type_free (gvariant_type); } - //g_base_info_unref ((GIBaseInfo *) return_type); - count_in_args = 0; - count_out_args = 0; - for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++) + for (n = 0; n < data->out_args->len; n++) { - GIArgInfo *arg; - GIDirection direction; - GArgument *arg_with_value; - - arg = g_callable_info_get_arg (callable, n); - direction = g_arg_info_get_direction (arg); - - arg_with_value = NULL; - switch (direction) - { - case GI_DIRECTION_IN: - /* do nothing */ - count_in_args++; - break; - - case GI_DIRECTION_OUT: - arg_with_value = args[count_out_args].v_pointer; - count_out_args++; - break; - - case GI_DIRECTION_INOUT: - /* return value is in the in GArgument, not the out one (that needs to be present) */ - arg_with_value = &in_args[count_in_args]; - count_out_args++; - count_in_args++; - break; - } - - if (arg_with_value != NULL) - { - add_out_arg (&builder, - return_type, - arg_with_value, - dbus_method->out_args[dbus_arg_num++]); - } - - g_base_info_unref ((GIBaseInfo *) arg); + 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); } - g_assert_cmpint (num_args, ==, count_out_args); - - ret = g_variant_builder_end (&builder); - return ret; + return g_variant_builder_end (&builder); } /* ---------------------------------------------------------------------------------------------------- */ @@ -351,99 +931,88 @@ free_one_arg (GArgument *arg, { GITypeTag tag; + g_return_if_fail (arg != NULL); + g_return_if_fail (type != NULL); + tag = g_type_info_get_tag (type); switch (tag) { + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_INT: + case GI_TYPE_TAG_UINT: + case GI_TYPE_TAG_DOUBLE: + /* do nothing */ + break; + case GI_TYPE_TAG_UTF8: switch (transfer) { case GI_TRANSFER_NOTHING: /* do nothing */ break; + case GI_TRANSFER_CONTAINER: g_assert_not_reached (); break; + case GI_TRANSFER_EVERYTHING: g_free (arg->v_string); break; } break; + case GI_TYPE_TAG_ARRAY: + /* TODO */ + break; + default: - /* Do nothing */ + g_error ("Don't know how to free type tag `%s' with transfer `%s'", + g_type_tag_to_string (tag), + transfer == GI_TRANSFER_NOTHING ? "nothing" : + (transfer == GI_TRANSFER_CONTAINER ? "container" : "everything")); break; } } +/* ---------------------------------------------------------------------------------------------------- */ + static void free_args (GArgument *return_value, GArgument *in_args, - guint num_in_args, GArgument *out_args, - GArgument *out_arg_values, - guint num_out_args, - GIFunctionInfo *method) + MethodData *data) { - GICallableInfo *callable; - guint count_in_args; - guint count_out_args; guint n; - GITypeInfo *return_type; + ArgData *ad; - callable = (GICallableInfo *) method; - - return_type = g_callable_info_get_return_type (callable); - if (g_type_info_get_tag (return_type) != GI_TYPE_TAG_VOID) + if (g_type_info_get_tag (data->return_value->type_info) != GI_TYPE_TAG_VOID) { - free_one_arg (return_value, - return_type, - g_callable_info_get_caller_owns (callable)); + ad = data->return_value; + free_one_arg (return_value, ad->type_info, ad->transfer); } - //g_base_info_unref ((GIBaseInfo *) return_type); - count_in_args = 0; - count_out_args = 0; - for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++) + /* want to skip this/self so start at 1 */ + for (n = 1; n < data->in_args->len; n++) { - GIArgInfo *arg; - GITypeInfo *type; - GIDirection direction; - GITransfer transfer; - GArgument *arg_to_free; - - arg = g_callable_info_get_arg (callable, n); - type = g_arg_info_get_type (arg); - direction = g_arg_info_get_direction (arg); - transfer = g_arg_info_get_ownership_transfer (arg); - - switch (direction) - { - case GI_DIRECTION_IN: - /* do nothing */ - arg_to_free = &in_args[count_in_args++]; - break; - - case GI_DIRECTION_OUT: - arg_to_free = &out_arg_values[count_out_args++]; - break; - - case GI_DIRECTION_INOUT: - /* should be unused */ - g_assert (out_args[count_out_args].v_pointer == NULL); - count_out_args++; - arg_to_free = &in_args[count_in_args++]; - break; - } - - free_one_arg (arg_to_free, - type, - transfer); + ad = data->in_args->pdata[n]; + free_one_arg (&in_args[n], ad->type_info, ad->transfer); + } - g_base_info_unref ((GIBaseInfo *) type); - g_base_info_unref ((GIBaseInfo *) arg); + for (n = 0; n < data->out_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); } - g_assert_cmpint (num_in_args, ==, count_in_args); - g_assert_cmpint (num_out_args, ==, count_out_args); } /* ---------------------------------------------------------------------------------------------------- */ @@ -465,13 +1034,12 @@ on_method_call (GDBusConnection *connection, ExportData *data = user_data; MethodData *method_data; GError *error; - GArgument return_value; GArgument *in_args; GArgument *out_args; GArgument *out_arg_values; - guint n; gboolean deferred; gboolean invocation_result; + GArgument return_value = {0}; in_args = NULL; out_args = NULL; @@ -482,23 +1050,18 @@ on_method_call (GDBusConnection *connection, method_data = g_hash_table_lookup (data->dbus_method_name_to_method_data, method_name); g_assert (method_data != NULL); - /* First argument is the object (e.g. this/self) and not included in the arg count */ - in_args = g_new0 (GArgument, method_data->num_gi_in_args + 1); - out_args = g_new0 (GArgument, method_data->num_gi_out_args); - out_arg_values = g_new0 (GArgument, method_data->num_gi_out_args); - n = 0; - in_args[n++].v_pointer = data->object; - - prepare_in_args (parameters, - in_args + 1, - method_data->num_gi_in_args, - method_data->method); - prepare_out_args (&return_value, - out_args, - out_arg_values, - method_data->num_gi_out_args, - method_data->method, - method_data->dbus_method); + 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); + + /* first is this/self */ + in_args[0].v_pointer = data->object; + + prepare_args (parameters, + in_args, + out_args, + out_arg_values, + method_data); g_static_private_set (&gobject_invocation, invocation, NULL); g_static_private_set (&gobject_invocation_object, g_object_ref (data->object), g_object_unref); @@ -507,9 +1070,9 @@ on_method_call (GDBusConnection *connection, error = NULL; invocation_result = g_function_info_invoke (method_data->method, in_args, - method_data->num_gi_in_args + 1, + method_data->in_args->len, out_args, - method_data->num_gi_out_args, + method_data->out_args->len, &return_value, &error); g_static_private_set (&gobject_invocation, NULL, NULL); @@ -525,12 +1088,10 @@ on_method_call (GDBusConnection *connection, if (!deferred) { GVariant *return_gvariant; - return_gvariant = process_out_args (&return_value, - in_args + 1, /* skip this/self */ - out_args, - method_data->num_gi_out_args, - method_data->method, - method_data->dbus_method); + return_gvariant = process_args (&return_value, + in_args, + out_args, + method_data); g_dbus_method_invocation_return_value (invocation, return_gvariant); g_variant_unref (return_gvariant); } @@ -539,12 +1100,9 @@ on_method_call (GDBusConnection *connection, if (in_args != NULL) { free_args (&return_value, - in_args + 1, /* skip this/self */ - method_data->num_gi_in_args, + in_args, out_args, - out_arg_values, - method_data->num_gi_out_args, - method_data->method); + method_data); g_free (in_args); g_free (out_args); g_free (out_arg_values); @@ -668,14 +1226,17 @@ get_arg_info (GICallableInfo *callable, GIArgInfo *arg, GError **error) { - GITypeTag tag; GITypeInfo *type; GDBusArgInfo *ret; - GVariantType *variant_type; + GVariantType *gvariant_type; + GVariantType *requested_gvariant_type; const gchar *type_from_annotation; const gchar *name; ret = NULL; + type = NULL; + gvariant_type = NULL; + requested_gvariant_type = NULL; type_from_annotation = NULL; if (arg != NULL) @@ -691,100 +1252,64 @@ get_arg_info (GICallableInfo *callable, type_from_annotation = g_callable_info_get_return_attribute (callable, "gdbus.signature"); } + requested_gvariant_type = NULL; if (type_from_annotation != NULL) - { - variant_type = g_variant_type_new (type_from_annotation); - /* TODO: check that @type is actually compatible with @type_from_annotation */ - } - else - { - tag = g_type_info_get_tag (type); - switch (tag) - { - case GI_TYPE_TAG_BOOLEAN: - variant_type = g_variant_type_new ("b"); - break; - case GI_TYPE_TAG_INT8: - variant_type = g_variant_type_new ("y"); - break; - case GI_TYPE_TAG_UINT8: - variant_type = g_variant_type_new ("y"); - break; - case GI_TYPE_TAG_INT16: - variant_type = g_variant_type_new ("n"); - break; - case GI_TYPE_TAG_UINT16: - variant_type = g_variant_type_new ("q"); - break; - case GI_TYPE_TAG_INT: - case GI_TYPE_TAG_INT32: - variant_type = g_variant_type_new ("i"); - break; - case GI_TYPE_TAG_UINT: - case GI_TYPE_TAG_UINT32: - variant_type = g_variant_type_new ("u"); - break; - case GI_TYPE_TAG_INT64: - variant_type = g_variant_type_new ("x"); - break; - case GI_TYPE_TAG_UINT64: - variant_type = g_variant_type_new ("t"); - break; - case GI_TYPE_TAG_DOUBLE: - variant_type = g_variant_type_new ("d"); - break; - case GI_TYPE_TAG_UTF8: - variant_type = g_variant_type_new ("s"); - break; - case GI_TYPE_TAG_FILENAME: - variant_type = g_variant_type_new ("ay"); - break; - default: - variant_type = NULL; - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Type tag `%s' not supported", - g_type_tag_to_string (tag)); - goto out; - } - } + requested_gvariant_type = g_variant_type_new (type_from_annotation); + gvariant_type = get_gvariant_type_for_gi_type (type, requested_gvariant_type, error); + if (gvariant_type == NULL) + goto out; ret = g_new0 (GDBusArgInfo, 1); ret->ref_count = 1; ret->name = g_strdup (name); - ret->signature = g_variant_type_dup_string (variant_type); + ret->signature = g_variant_type_dup_string (gvariant_type); + + g_print (" Using signature `%s' for param `%s'\n", ret->signature, ret->name); out: - g_base_info_unref ((GIBaseInfo *) type); + if (gvariant_type != NULL) + g_variant_type_free (gvariant_type); + if (requested_gvariant_type != NULL) + g_variant_type_free (requested_gvariant_type); + if (type != NULL) + g_base_info_unref ((GIBaseInfo *) type); return ret; } -static GDBusMethodInfo * -get_method_info (GIFunctionInfo *method, +static MethodData * +get_method_data (GIFunctionInfo *method, const gchar *dbus_name, - gint *num_gi_in_args, - gint *num_gi_out_args, GError **error) { - GDBusMethodInfo *ret; + MethodData *ret; GICallableInfo *callable; GITypeInfo *return_type; - GPtrArray *in_args; - GPtrArray *out_args; + GPtrArray *in_dbus_args; + GPtrArray *out_dbus_args; + ArgData *ad; guint n; - ret = NULL; - in_args = g_ptr_array_new (); - out_args = g_ptr_array_new (); + in_dbus_args = g_ptr_array_new (); + out_dbus_args = g_ptr_array_new (); + + 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); - *num_gi_in_args = 0; - *num_gi_out_args = 0; + /* this/self */ + ad = arg_data_new (); + g_ptr_array_add (ret->in_args, ad); callable = (GICallableInfo *) method; + g_print ("Using dbus name `%s' for function `%s'\n", dbus_name, g_base_info_get_name ((GIBaseInfo *) method)); + /* Handle return value, if any */ return_type = g_callable_info_get_return_type (callable); + ad = arg_data_new (); + ad->type_info = g_base_info_ref ((GIBaseInfo *) return_type); + ad->transfer = g_callable_info_get_caller_owns (callable); if (g_type_info_get_tag (return_type) != GI_TYPE_TAG_VOID) { GDBusArgInfo *arg_info; @@ -795,81 +1320,141 @@ get_method_info (GIFunctionInfo *method, "Error processing return value of symbol `%s': ", g_function_info_get_symbol (method)); g_base_info_unref ((GIBaseInfo *) return_type); + method_data_free (ret); + ret = NULL; goto out; } - g_ptr_array_add (out_args, arg_info); + ad->dbus_arg_info = g_dbus_arg_info_ref (arg_info); + g_ptr_array_add (out_dbus_args, arg_info); } + ret->return_value = ad; //g_base_info_unref ((GIBaseInfo *) return_type); /* Go through all parameters */ for (n = 0; n < (guint) g_callable_info_get_n_args (callable); n++) { GIArgInfo *arg; + GITypeInfo *type; GIDirection direction; GDBusArgInfo *arg_info; + gboolean not_on_dbus; + guint m; + + /* Don't export arg on D-Bus if it's used for another arg (e.g. a length parameter for an array) */ + not_on_dbus = FALSE; arg = g_callable_info_get_arg (callable, n); + type = g_arg_info_get_type (arg); - arg_info = get_arg_info (callable, arg, error); - if (arg_info == NULL) + ad = arg_data_new (); + 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); + + /* 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++) { - g_prefix_error (error, - "Error processing argument `%s' of symbol `%s': ", - g_base_info_get_name ((GIBaseInfo *) arg), - g_function_info_get_symbol (method)); - g_base_info_unref ((GIBaseInfo *) arg); - goto out; + GIArgInfo *other_arg; + GITypeInfo *other_type; + other_arg = g_callable_info_get_arg (callable, m); + other_type = g_arg_info_get_type (other_arg); + /* get_array_length() assumes first arg is this/self */ + if (g_type_info_get_array_length (other_type) == (gint) n + 1) + { + not_on_dbus = TRUE; + ad->is_array_len_for_position = n; + } + g_base_info_unref ((GIBaseInfo *) other_type); + g_base_info_unref ((GIBaseInfo *) other_arg); } + /* Set if this is an array using another arg as a length parameter */ + ad->array_len_position = g_type_info_get_array_length (type); + + arg_info = NULL; + if (!not_on_dbus) + { + arg_info = get_arg_info (callable, arg, error); + if (arg_info == NULL) + { + g_prefix_error (error, + "Error processing argument `%s' of symbol `%s': ", + g_base_info_get_name ((GIBaseInfo *) arg), + g_function_info_get_symbol (method)); + g_base_info_unref ((GIBaseInfo *) arg); + g_base_info_unref ((GIBaseInfo *) type); + method_data_free (ret); + ret = NULL; + goto out; + } + } + + ad->dbus_arg_info = arg_info != NULL ? g_dbus_arg_info_ref (arg_info) : NULL; + direction = g_arg_info_get_direction (arg); switch (direction) { case GI_DIRECTION_IN: - g_ptr_array_add (in_args, arg_info); - *num_gi_in_args += 1; + if (arg_info != NULL) + g_ptr_array_add (in_dbus_args, arg_info); + g_ptr_array_add (ret->in_args, ad); break; case GI_DIRECTION_OUT: - g_ptr_array_add (out_args, arg_info); - *num_gi_out_args += 1; + if (arg_info != NULL) + g_ptr_array_add (out_dbus_args, arg_info); + g_ptr_array_add (ret->out_args, ad); break; case GI_DIRECTION_INOUT: { - gchar *s; - s = g_strdup_printf ("in_%s", arg_info->name); - g_free (arg_info->name); - arg_info->name = s; - g_ptr_array_add (in_args, arg_info); - *num_gi_in_args += 1; + gchar *in_arg_name; + gchar *out_arg_name; + + in_arg_name = g_strdup_printf ("in_%s", arg_info->name); + out_arg_name = g_strdup_printf ("out_%s", arg_info->name); - arg_info = get_arg_info (callable, arg, NULL); - g_assert (arg_info != NULL); - s = g_strdup_printf ("out_%s", arg_info->name); g_free (arg_info->name); - arg_info->name = s; - g_ptr_array_add (out_args, arg_info); - *num_gi_out_args += 1; - break; + 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); + + 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); + + ad->inout_in_arg_offset = ret->in_args->len - 1; + + g_ptr_array_add (ret->out_args, ad); } + break; } + + if (arg_info != NULL) + g_dbus_arg_info_unref (arg_info); g_base_info_unref ((GIBaseInfo *) arg); + g_base_info_unref ((GIBaseInfo *) type); } - g_ptr_array_add (in_args, NULL); - g_ptr_array_add (out_args, NULL); + g_ptr_array_add (in_dbus_args, NULL); + g_ptr_array_add (out_dbus_args, NULL); - ret = g_new0 (GDBusMethodInfo, 1); - ret->ref_count = 1; - ret->name = g_strdup (dbus_name); - g_ptr_array_ref (in_args); - g_ptr_array_ref (out_args); - ret->in_args = (GDBusArgInfo **) g_ptr_array_free (in_args, FALSE); - ret->out_args = (GDBusArgInfo **) g_ptr_array_free (out_args, FALSE); + ret->dbus_method = g_new0 (GDBusMethodInfo, 1); + ret->dbus_method->ref_count = 1; + ret->dbus_method->name = g_strdup (dbus_name); + g_ptr_array_ref (in_dbus_args); + g_ptr_array_ref (out_dbus_args); + ret->dbus_method->in_args = (GDBusArgInfo **) g_ptr_array_free (in_dbus_args, FALSE); + ret->dbus_method->out_args = (GDBusArgInfo **) g_ptr_array_free (out_dbus_args, FALSE); out: - g_ptr_array_foreach (in_args, (GFunc) g_dbus_arg_info_unref, NULL); - g_ptr_array_foreach (out_args, (GFunc) g_dbus_arg_info_unref, NULL); - g_ptr_array_unref (in_args); - g_ptr_array_unref (out_args); + g_ptr_array_foreach (in_dbus_args, (GFunc) g_dbus_arg_info_unref, NULL); + g_ptr_array_foreach (out_dbus_args, (GFunc) g_dbus_arg_info_unref, NULL); + g_ptr_array_unref (in_dbus_args); + g_ptr_array_unref (out_dbus_args); return ret; } @@ -926,17 +1511,12 @@ compute_introspection_data (GObject *object, dbus_name = g_base_info_get_attribute ((GIBaseInfo *) method, "gdbus.method"); if (dbus_name != NULL) { - GDBusMethodInfo *method_info; MethodData *method_data; - gint num_gi_in_args; - gint num_gi_out_args; - method_info = get_method_info (method, + method_data = get_method_data (method, dbus_name, - &num_gi_in_args, - &num_gi_out_args, error); - if (method_info == NULL) + if (method_data == NULL) { g_ptr_array_foreach (method_infos, (GFunc) g_dbus_method_info_unref, NULL); g_ptr_array_unref (method_infos); @@ -944,13 +1524,9 @@ compute_introspection_data (GObject *object, ret = NULL; goto out; } - g_ptr_array_add (method_infos, method_info); + g_ptr_array_add (method_infos, method_data->dbus_method); - method_data = g_new0 (MethodData, 1); - method_data->method = g_base_info_ref ((GIBaseInfo *) method); - method_data->dbus_method = g_dbus_method_info_ref (method_info); - method_data->num_gi_in_args = num_gi_in_args; - method_data->num_gi_out_args = num_gi_out_args; + method_data_dump (method_data, 0); g_hash_table_insert (data->dbus_method_name_to_method_data, g_strdup (dbus_name), diff --git a/src/myfrobnicator.c b/src/myfrobnicator.c index fc78fde..399ada5 100644 --- a/src/myfrobnicator.c +++ b/src/myfrobnicator.c @@ -21,6 +21,8 @@ #include "config.h" +#include <stdlib.h> + #include "gdbusgi.h" #include "myfrobnicator.h" @@ -272,3 +274,55 @@ my_frobnicator_poke_path (MyFrobnicator *frobnicator, return g_strdup_printf ("/another/object/path/here%s", object_path); } + +/** + * my_frobnicator_test_arrays: + * @frobnicator: + * @carray_ai: (array length=carray_ai_len): + * @carray_ai_len: + * @carray_as: + * @gbytearray_ay: (element-type guint8): + * @garray_ai: (element-type gint): + * @garray_ad: (element-type gdouble): + * @gptrarray_as: (element-type utf8): + * @error: + * + * Returns: The sum of all elements. + * + * Attributes: (gdbus.method TestArrays) + */ +gdouble +my_frobnicator_test_arrays (MyFrobnicator *frobnicator, + //gint *carray_ai, + //gint carray_ai_len, + const gchar *const *carray_as, + GByteArray *gbytearray_ay, + GArray *garray_ai, + GArray *garray_ad, + GPtrArray *gptrarray_as) +{ + gdouble ret; + guint n; + + ret = 0.0; + + //for (n = 0; n < carray_ai_len; n++) + // ret += carray_ai[n]; + + for (n = 0; carray_as[n] != NULL; n++) + ret += atof (carray_as[n]); + + for (n = 0; n < gbytearray_ay->len; n++) + ret += gbytearray_ay->data[n]; + + for (n = 0; n < garray_ai->len; n++) + ret += g_array_index (garray_ai, gint, n); + + for (n = 0; n < garray_ad->len; n++) + ret += g_array_index (garray_ad, gdouble, n); + + for (n = 0; n < gptrarray_as->len; n++) + ret += atof (gptrarray_as->pdata[n]); + + return ret; +} diff --git a/src/myfrobnicator.h b/src/myfrobnicator.h index 92686b8..039f853 100644 --- a/src/myfrobnicator.h +++ b/src/myfrobnicator.h @@ -106,6 +106,14 @@ const gchar *my_frobnicator_return_const_str (MyFrobnicator *frobnicator, gchar *my_frobnicator_poke_path (MyFrobnicator *frobnicator, const gchar *object_path); +gdouble my_frobnicator_test_arrays (MyFrobnicator *frobnicator, + //gint *carray_ai, + //gint carray_ai_len, + const gchar *const *carray_as, + GByteArray *gbytearray_ay, + GArray *garray_ai, + GArray *garray_ad, + GPtrArray *gptrarray_as); G_END_DECLS @@ -21,7 +21,9 @@ #include "config.h" +#include <math.h> #include <gio/gio.h> + #include "gdbusgi.h" #include <girepository.h> @@ -51,6 +53,35 @@ 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 ("(['100', '200', '300'], " + " [@y 10, 20, 30], " + " [1, 2, 3], " + " [0.1, 0.2, 0.3], " + " ['0.01', '0.02', '0.03'])"), + 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 - 666.66), <, 1e-10); + g_variant_unref (ret); +} + +static void run_test (GDBusConnection *connection) { GError *error; @@ -245,6 +276,8 @@ run_test (GDBusConnection *connection) } g_variant_unref (ret); + run_array_test (connection); + } static gpointer |