DBUS: data type or container type

数据类型

其实DBUS的数据类型在 bluetoothctl client tool 中的dbus数据模型就有记录和说明过。通过基本类型数据进行嵌套可以组合成复杂数据类型,一般可以用简称表示,例如 a{sv} 。如何将数据进行构造和解析才是难点和重点。

Numeric

数字的数据类型涉及: b, y, n, q, i, u, x, t, h, d

Character Equivalent C type
b gboolean
y guchar
n gint16
q guint16
i gint32
u guint32
x gint64
t guint64
h gint32 (handle)
d gdouble
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*
gcc main.c -o main `pkg-config --libs --cflags dbus-1` `pkg-config --libs --cflags glib-2.0` `pkg-config --libs --cflags gio-2.0`
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include <glib.h>
#include <gio/gio.h>
#include <glib/gprintf.h>

int main(int argc, char *argv[])
{
// 构造
GVariant *value1, *value2, *value3, *value4;
value1 = g_variant_new ("y", 200);
value2 = g_variant_new ("b", TRUE);
value3 = g_variant_new ("d", 37.5);
value4 = g_variant_new ("x", G_GINT64_CONSTANT (998877665544332211));

// 解析
guchar byte;
gdouble floating;
gboolean truth;
gint64 bignum;
g_variant_get (value1, "y", &byte); /* ignore the value. */
g_variant_get (value2, "b", &truth);
g_variant_get (value3, "d", &floating);
g_variant_get (value4, "x", &bignum);

// 打印
g_printf("value1(y): %u\n", byte);
g_printf("value2(b): %s\n", truth ? "ture":"false");
g_printf("value3(d): %.1f\n", floating);
g_printf("value4(x): %ld\n", bignum);

g_variant_unref(value1);
g_variant_unref(value2);
g_variant_unref(value3);
g_variant_unref(value4);

return 0;
}

String

字符串涉及:s, o, g

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/*
gcc main.c -o main `pkg-config --libs --cflags dbus-1` `pkg-config --libs --cflags glib-2.0` `pkg-config --libs --cflags gio-2.0`
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include <glib.h>
#include <gio/gio.h>
#include <glib/gprintf.h>

int main(int argc, char *argv[])
{
GVariant *value1, *value2, *value3;

value1 = g_variant_new ("s", "hello world!");
value2 = g_variant_new ("o", "/must/be/a/valid/path");
value3 = g_variant_new ("g", "iias");


gchar *str, *object_path, *signature;

g_variant_get (value1, "s", &str);
g_variant_get (value2, "o", &object_path);
g_variant_get (value3, "g", &signature);

g_printf("value1(s): %s'\n", str);
g_printf("value1(s): %s'\n", object_path);
g_printf("value1(s): %s'\n", signature);
g_free (str);
g_free (object_path);
g_free (signature);

g_variant_unref(value1);
g_variant_unref(value2);
g_variant_unref(value3);

return 0;
}

注意:当g_variant_get() 遇到 ‘s’ ,’o’, ‘g’ 时,会创建一块新的内容,然后把要返回的字符串拷贝到这个内容中,这块内存返回给给一个指向gchar * 的指针,所以传入函数参数类型是 gchar ** ,最后使用完后,需要用户使用g_free() 进行释放。

Array

数组:a

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/*
gcc main.c -o main `pkg-config --libs --cflags dbus-1` `pkg-config --libs --cflags glib-2.0` `pkg-config --libs --cflags gio-2.0`
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include <glib.h>
#include <gio/gio.h>
#include <glib/gprintf.h>

int main(int argc, char *argv[])
{
// 构造
GVariantBuilder *builder;
GVariant *value;

builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
g_variant_builder_add(builder, "s", "when");
g_variant_builder_add(builder, "s", "in");
g_variant_builder_add(builder, "s", "the");
g_variant_builder_add(builder, "s", "course");
value = g_variant_new("as", builder);
g_variant_builder_unref(builder);

// 解析
GVariantIter *iter;
gchar *str;

g_variant_get(value, "as", &iter);
while (g_variant_iter_loop(iter, "s", &str))
g_print("%s\n", str);
g_variant_iter_free(iter);

g_variant_unref(value);

return 0;
}

Tuple

元组:()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
gcc main.c -o main `pkg-config --libs --cflags dbus-1` `pkg-config --libs --cflags glib-2.0` `pkg-config --libs --cflags gio-2.0`
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include <glib.h>
#include <gio/gio.h>
#include <glib/gprintf.h>

int main(int argc, char *argv[])
{
GVariant *value1, *value2;

value1 = g_variant_new("(s(ii))", "Hello", 55, 77);

gchar *string;
gint x, y;

g_variant_get(value1, "(s(ii))", &string, &x, &y);
g_printf("%s, %d, %d\n", string, x, y);
g_free(string);

return 0;
}

Dictionary

字典:{}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/*
gcc main.c -o main `pkg-config --libs --cflags dbus-1` `pkg-config --libs --cflags glib-2.0` `pkg-config --libs --cflags gio-2.0`
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include <glib.h>
#include <gio/gio.h>
#include <glib/gprintf.h>

int main(int argc, char *argv[])
{
// 构造
GVariantBuilder *b;
GVariant *dict;

b = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
g_variant_builder_add(b, "{sv}", "name", g_variant_new_string("foo"));
g_variant_builder_add(b, "{sv}", "timeout", g_variant_new_int32(10));
dict = g_variant_builder_end(b);
g_variant_builder_unref(b);

// 解析
GVariantIter iter;
GVariant *value;
gchar *key;
g_variant_iter_init(&iter, dict);
while (g_variant_iter_next (&iter, "{sv}", &key, &value))
{
const gchar *type = g_variant_get_type_string(value);
switch (*type)
{
case 's':
g_printf("%s(%s): %s\n", key, type, g_variant_get_string(value, NULL));
break;
case 'i':
g_printf("%s(%s): %d\n", key, type, g_variant_get_int32(value));
break;
default:
break;
}

// must free data for ourselves
g_variant_unref(value);
g_free(key);
}
g_variant_unref(dict);

return 0;
}

注意:通过g_variant_iter_next() 获取的key和value,在while循环内部使用完后,需要用户进行释放。通过g_variant_iter_init() 获取的dict,在使用完后,也需要用户进行释放。但是有特殊的地方,若第二个参数是{&sv},那么对应的key就无需用户释放。

Multiple

复合类型,即不同类型的嵌套,例如:(a{sv})

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
/*
gcc main.c -o main `pkg-config --libs --cflags dbus-1` `pkg-config --libs --cflags glib-2.0` `pkg-config --libs --cflags gio-2.0`
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

#include <glib.h>
#include <gio/gio.h>
#include <glib/gprintf.h>

int main(int argc, char *argv[])
{
// 构造
GVariantBuilder *b;
GVariant *dict, *tuple;

b = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
g_variant_builder_add(b, "{sv}", "name", g_variant_new_string("foo"));
g_variant_builder_add(b, "{sv}", "timeout", g_variant_new_int32(10));
dict = g_variant_builder_end(b);
g_variant_builder_unref(b);
tuple = g_variant_new_tuple(&dict, 1);

// 解析
GVariantIter *iter;
GVariant *value;
gchar *key;

g_variant_get(tuple, "(a{sv})", &iter);
while (g_variant_iter_next (iter, "{sv}", &key, &value))
{
const gchar *type = g_variant_get_type_string(value);
switch (*type)
{
case 's':
g_printf("%s(%s): %s\n", key, type, g_variant_get_string(value, NULL));
break;
case 'i':
g_printf("%s(%s): %d\n", key, type, g_variant_get_int32(value));
break;
default:
break;
}

// must free data for ourselves
g_variant_unref(value);
g_free(key);
}
g_variant_unref(tuple);

return 0;
}

内存释放

g_variant_iter_free()

g_variant_iter_free() 可以释放由这两个函数返回的变量的内存:g_variant_iter_new() or g_variant_iter_copy()

1
2
3
4
void
g_variant_iter_free (
GVariantIter* iter
)

参考来源

1、BlueZ Part 3: Understanding DBUS – Container type system – (2)

2、BlueZ Part 2: Understanding DBUS – Basic type system – (1)

3、GVariant 格式字符串

4、Dbus-glib

5、dbus介绍与例子