---
ell/dbus-message.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++++++
ell/dbus.h | 4 ++
2 files changed, 129 insertions(+)
diff --git a/ell/dbus-message.c b/ell/dbus-message.c
index 159df82..e618cf7 100644
--- a/ell/dbus-message.c
+++ b/ell/dbus-message.c
@@ -1584,6 +1584,131 @@ LIB_EXPORT bool l_dbus_message_builder_leave_variant(
return l_dbus_message_builder_leave_container(builder, 'v');
}
+/**
+ * l_dbus_message_builder_append_from_iter:
+ * @builder: message builder to receive a new value
+ * @from: message iterator to have its position moved by one value
+ *
+ * Copy one value from a message iterator onto a message builder. The
+ * value's signature is also copied.
+ *
+ * Returns: whether the value was correctly copied. On failure both
+ * the @from iterator and the @builder may have their positions
+ * moved to somewhere within the new value if it's of a
+ * container type.
+ **/
+LIB_EXPORT bool l_dbus_message_builder_append_from_iter(
+ struct l_dbus_message_builder *builder,
+ struct l_dbus_message_iter *from)
+{
+ static const char *simple_types = "sogybnqiuxtd";
+ char type = from->sig_start[from->sig_pos];
+ char container_type;
+ char signature[256];
+ struct l_dbus_message_iter iter;
+ void *basic_ptr;
+ uint64_t basic;
+ uint32_t uint32_val;
+ int fd;
+ bool (*get_basic)(struct l_dbus_message_iter *, char, void *);
+ bool (*enter_func)(struct l_dbus_message_iter *,
+ struct l_dbus_message_iter *);
+ bool (*enter_struct)(struct l_dbus_message_iter *,
+ struct l_dbus_message_iter *);
+ bool (*enter_array)(struct l_dbus_message_iter *,
+ struct l_dbus_message_iter *);
+ bool (*enter_variant)(struct l_dbus_message_iter *,
+ struct l_dbus_message_iter *);
+
+ if (_dbus_message_is_gvariant(from->message)) {
+ get_basic = _gvariant_iter_next_entry_basic;
+ enter_struct = _gvariant_iter_enter_struct;
+ enter_array = _gvariant_iter_enter_array;
+ enter_variant = _gvariant_iter_enter_variant;
+ } else {
+ get_basic = _dbus1_iter_next_entry_basic;
+ enter_struct = _dbus1_iter_enter_struct;
+ enter_array = _dbus1_iter_enter_array;
+ enter_variant = _dbus1_iter_enter_variant;
+ }
+
+ if (strchr(simple_types, type)) {
+ if (strchr("sog", type)) {
+ if (!get_basic(from, type, &basic_ptr))
+ return false;
+ } else {
+ basic_ptr = &basic;
+
+ if (!get_basic(from, type, basic_ptr))
+ return false;
+ }
+
+ if (!l_dbus_message_builder_append_basic(builder, type,
+ basic_ptr))
+ return false;
+
+ return true;
+ }
+
+ switch (type) {
+ case 'h':
+ if (!get_basic(from, type, &uint32_val))
+ return false;
+
+ if (uint32_val >= from->message->num_fds)
+ return false;
+
+ fd = fcntl(from->message->fds[uint32_val], F_DUPFD_CLOEXEC, 3);
+
+ uint32_val = builder->message->num_fds;
+ builder->message->fds[builder->message->num_fds++] = fd;
+
+ if (!l_dbus_message_builder_append_basic(builder, type,
+ &uint32_val))
+ return false;
+
+ return true;
+ case '(':
+ enter_func = enter_struct;
+ container_type = DBUS_CONTAINER_TYPE_STRUCT;
+ break;
+ case '{':
+ enter_func = enter_struct;
+ container_type = DBUS_CONTAINER_TYPE_DICT_ENTRY;
+ break;
+ case 'a':
+ enter_func = enter_array;
+ container_type = DBUS_CONTAINER_TYPE_ARRAY;
+ break;
+ case 'v':
+ enter_func = enter_variant;
+ container_type = DBUS_CONTAINER_TYPE_VARIANT;
+ break;
+ default:
+ return false;
+ }
+
+ if (!enter_func(from, &iter))
+ return false;
+
+ memcpy(signature, iter.sig_start, iter.sig_len);
+ signature[iter.sig_len] = '\0';
+
+ if (!l_dbus_message_builder_enter_container(builder,
+ container_type, signature))
+ return false;
+
+ while (iter.sig_pos < iter.sig_len)
+ if (!l_dbus_message_builder_append_from_iter(builder, &iter))
+ return false;
+
+ if (!l_dbus_message_builder_leave_container(builder,
+ container_type))
+ return false;
+
+ return true;
+}
+
LIB_EXPORT struct l_dbus_message *l_dbus_message_builder_finalize(
struct l_dbus_message_builder *builder)
{
diff --git a/ell/dbus.h b/ell/dbus.h
index 011d59a..29253b6 100644
--- a/ell/dbus.h
+++ b/ell/dbus.h
@@ -188,6 +188,10 @@ bool l_dbus_message_builder_enter_variant(
bool l_dbus_message_builder_leave_variant(
struct l_dbus_message_builder *builder);
+bool l_dbus_message_builder_append_from_iter(
+ struct l_dbus_message_builder *builder,
+ struct l_dbus_message_iter *from);
+
struct l_dbus_message *l_dbus_message_builder_finalize(
struct l_dbus_message_builder *builder);
--
2.5.0