Sending a byte array (type `ay`) over D-Bus using GDBus
Asked Answered
E

4

6

I am trying to a byte array over D-Bus using the GDBus bindings. Can you please let me know how I can achive that. I tried googling but didnt help.

Byte array contains a image file so cannot be converted to charbytearray

Any help is appriciated

Earldom answered 8/4, 2014 at 12:49 Comment(0)
D
0

This question has some good ideas in the answers including for passing large amounts of data by writing the data to a file and passing the filename, or using a named pipe. Writing to a file and passing the file name might be the easiest to implement.

Dammar answered 10/4, 2014 at 23:38 Comment(0)
F
11

I did some tests using an XML where I used the type ay. This works well with the QT binding (generated with qdbusxml2cpp) where it translates into QByteArray however it seems that it doesn't work with the glib binding (generated with gdbus-codegen) where it translates in gchar * and it seems you lose what's after \0 - because somehow it's handled as a string. However you will find that:

This automatic mapping can be turned off by using the annotation org.gtk.GDBus.C.ForceGVariant - if used then a GVariant is always exchanged instead of the corresponding native C type. This annotation may be convenient to use when using bytestrings (type-string ay) for data that could have embedded NUL bytes.

Which means according to https://developer.gnome.org/gio/stable/gdbus-codegen.html that you could handle it as GVariant. I tested this by adding the tag for annotation org.gtk.GDBus.C.ForceGVariant <annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/> on each arg and it works.

Fisticuffs answered 23/7, 2014 at 10:40 Comment(3)
I think this one is the correct answer to the question. And i would rather use ''--annotate'' option along with gdbus-codegen than adding it to the xml file @Fisticuffs thanks ..!Patten
Can you please post a sample xml file with the annotation? this not working for me.Patten
Just in case some case someone else is puzzled by how to create a "ay" GVariant from char *: gchar *data = ...; GBytes *bytes = g_bytes_new(data, data_size); g_variant_new_from_bytes(G_VARIANT_TYPE_BYTESTRING, bytes, TRUE);Several
M
4

Actually, instead of using type "ay", you can use "a(y)". The glib binding would translate "a(y)" to GVariant*.

And then you can use "GVariant" handling to deal with the parameter.

e.g. the xml file

<method name="parsePacket">
  <arg direction="in" name="message" type="a(y)">
    <doc>
      <line>type: const Uint8 *</line>
    </doc>
  </arg>
</method>

Generated method:

gboolean (*handle_parse_packet) (
IDbusObject *object, GDBusMethodInvocation *invocation, GVariant *arg_message);

gboolean idbusobject_call_parse_packet_sync (
   IDbusObject *proxy,
   GVariant *arg_message,
   GCancellable *cancellable,
  GError **error);

You can extract and insert data using "GVariant" method.

Insert data at client side:

void parsePacket (unsigned char* arg_message, guint16 arg_length)
{
    GVariantBuilder *builder;
    GVariant *value;

    builder = g_variant_builder_new (G_VARIANT_TYPE ("a(y)"));
    for (int i = 0; i < arg_length; i++)
    {
        g_variant_builder_add (builder, "(y)", arg_message[i]);
    }
    value = g_variant_new ("a(y)", builder);
    g_variant_builder_unref (builder);

    idbusobject_call_parse_packet_sync(proxy,
        value,
        NULL,
        NULL);
}

Extract data at server side:

gboolean handleParsePacket (
    IDbusObject *object,
    GDBusMethodInvocation *invocation,
    GVariant *arg_message)
{
    unsigned char byteArray[2048];
    int actualLength = 0;

    GVariantIter *iter;
    guchar str;

    g_variant_get (arg_message, "a(y)", &iter);
    while (g_variant_iter_loop (iter, "(y)", &str))
    {
        byteArray[actualLength++] = str;
    }
    g_variant_iter_free (iter);

    idbusobject_complete_parse_packet( object, invocation);

    return (TRUE);
}
Momentous answered 18/3, 2015 at 10:32 Comment(1)
Using type a(y) instead of ay is a hacky workaround; you should be using the org.gtk.GDBus.C.ForceGVariant annotation instead, as per cyrax’s answer.Carruth
D
0

This question has some good ideas in the answers including for passing large amounts of data by writing the data to a file and passing the filename, or using a named pipe. Writing to a file and passing the file name might be the easiest to implement.

Dammar answered 10/4, 2014 at 23:38 Comment(0)
F
0

At the client side, you could do it easier by calling the g_variant_new_from_data() method:

GVariant* convertByteArrayToVariant(unsigned char* arg_message, guint16 arg_length)
{
    return g_variant_new_from_data(
        G_VARIANT_TYPE ("a(y)"),
        arg_message,
        arg_length,
        TRUE,
        NULL,
        NULL);
}

Or, if you have a populated a GByteArray*, you could do it like this:

GVariant* convertByteArrayToVariant(GByteArray* array)
{
    return g_variant_new_from_data(
        G_VARIANT_TYPE ("a(y)"),
        array->data,
        array->len,
        TRUE,
        NULL,
        NULL);
}
Fulviah answered 10/6, 2016 at 6:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.