From 1b50ad9839b4b77003933d41aee8f0f30b0a557a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Pavel=20B=C5=99ezina?= <pbrezina@redhat.com>
Date: Wed, 18 Mar 2015 13:01:07 +0100
Subject: [PATCH 3/8] sbus: add a{sas} get invoker

---
 src/sbus/sbus_codegen                    |  32 +++++--
 src/sbus/sssd_dbus_invokers.c            | 110 ++++++++++++++++++++++
 src/sbus/sssd_dbus_invokers.h            |   4 +
 src/tests/sbus_codegen_tests.c           | 157 +++++++++++++++++++++++++++++++
 src/tests/sbus_codegen_tests.xml         |  10 +-
 src/tests/sbus_codegen_tests_generated.c |  23 +++++
 src/tests/sbus_codegen_tests_generated.h |  63 ++++++++-----
 7 files changed, 365 insertions(+), 34 deletions(-)

diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen
index 7d2127508830e4040081557dcdf505dc261d784e..384972a14888ffaed23872f100a1dd39dde9449b 100755
--- a/src/sbus/sbus_codegen
+++ b/src/sbus/sbus_codegen
@@ -125,12 +125,15 @@ class Typed(Base):
         self.type = type
         self.is_basic = False
         self.is_array = False
+        self.is_dictionary = False
         self.dbus_constant = None
         self.dbus_type = None
         self.sssd_type = None
         if type[0] == 'a':
             type = type[1:]
             self.is_array = True
+        if "{" in type:
+            self.is_dictionary = True
         if type in BASIC_TYPES:
             (self.dbus_constant, self.dbus_type, self.sssd_type) = BASIC_TYPES[type]
             # If types are not identical, we can't do array (yet)
@@ -192,16 +195,29 @@ class Property(Typed):
             raise DBusXmlException('Invalid access type %s'%self.access)
     def fq_c_name(self):
         return "%s_%s" % (self.iface.c_name(), self.c_name())
+    def get_invoker_name(self):
+        type = self.type
+        type = type.replace("{", "DO")
+        type = type.replace("}", "DE")
+        return type
+    def get_invoker_signature(self, name):
+        sig = "void (*%s)(struct sbus_request *, void *data, " % (name)
+        if self.is_dictionary:
+            sig += "hash_table_t **"
+        elif self.is_array:
+            sig += "%s**, int *" % (self.sssd_type)
+        else:
+            sig += "%s*" % (self.sssd_type)
+        sig += ")"
+        return sig
+    
+    
     def getter_name(self):
         return "get_%s" % self.c_name()
     def getter_invoker_name(self):
-        return "sbus_invoke_get_%s" % self.type
-    def getter_signature(self, name):
-        sig = "void (*%s)(struct sbus_request *, void *data, %s *" % (name, self.sssd_type)
-        if self.is_array:
-            sig += " *, int *"
-        sig += ")"
-        return sig
+        return "sbus_invoke_get_%s" % self.get_invoker_name()
+    def getter_signature(self):
+        return self.get_invoker_signature(self.getter_name())
 
 class Interface(Base):
     def __init__(self, name):
@@ -253,7 +269,7 @@ def method_function_pointer(meth, name, with_names=False):
              method_arg_types(meth.in_args, with_names))
 
 def property_handlers(prop):
-    return prop.getter_signature(prop.getter_name())
+    return prop.getter_signature()
 
 def forward_method_invoker(signature, args):
     out("")
diff --git a/src/sbus/sssd_dbus_invokers.c b/src/sbus/sssd_dbus_invokers.c
index df9104f63fb24e1066ac8897d403167962376a17..71ee6c0134a9451a9974730fe8428d67dde3d3bb 100644
--- a/src/sbus/sssd_dbus_invokers.c
+++ b/src/sbus/sssd_dbus_invokers.c
@@ -303,6 +303,116 @@ int sbus_invoke_get_ao(DBusMessageIter *iter,
                                  DBUS_TYPE_OBJECT_PATH, iter);
 }
 
+int sbus_invoke_get_aDOsasDE(DBusMessageIter *iter,
+                             struct sbus_request *sbus_req,
+                             void *function_ptr)
+{
+    void (*handler_fn)(struct sbus_request *, void *, hash_table_t **);
+    DBusMessageIter it_array;
+    DBusMessageIter it_dict;
+    DBusMessageIter it_values;
+    hash_table_t *table;
+    struct hash_iter_context_t *table_iter = NULL;
+    hash_entry_t *entry;
+    const char **values;
+    dbus_bool_t dbret;
+    errno_t ret;
+    int i;
+
+    handler_fn = function_ptr;
+    handler_fn(sbus_req, sbus_req->intf->handler_data, &table);
+
+    dbret = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                    DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                    DBUS_TYPE_STRING_AS_STRING
+                    DBUS_TYPE_ARRAY_AS_STRING
+                    DBUS_TYPE_STRING_AS_STRING
+                    DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &it_array);
+    if (!dbret) {
+        ret = EIO;
+        goto done;
+    }
+
+    /* iterate over keys */
+
+    if (table == NULL) {
+        ret = EOK;
+        goto done;
+    }
+
+    table_iter = new_hash_iter_context(table);
+    while ((entry = table_iter->next(table_iter)) != NULL) {
+        if (entry->key.type != HASH_KEY_STRING || entry->key.str == NULL
+                || entry->value.type != HASH_VALUE_PTR
+                || entry->value.ptr == NULL) {
+            continue;
+        }
+
+        dbret = dbus_message_iter_open_container(&it_array,
+                                                 DBUS_TYPE_DICT_ENTRY, NULL,
+                                                 &it_dict);
+        if (!dbret) {
+            ret = EIO;
+            goto done;
+        }
+
+        /* append key as dict entry key */
+
+        dbret = dbus_message_iter_append_basic(&it_dict,
+                                               DBUS_TYPE_STRING,
+                                               &entry->key.str);
+        if (!dbret) {
+            ret = EIO;
+            goto done;
+        }
+
+        /* iterate over values */
+
+        dbret = dbus_message_iter_open_container(&it_dict,
+                                                 DBUS_TYPE_ARRAY,
+                                                 DBUS_TYPE_STRING_AS_STRING,
+                                                 &it_values);
+        if (!dbret) {
+            ret = EIO;
+            goto done;
+        }
+
+        values = entry->value.ptr;
+        for (i = 0; values[i] != NULL; i++) {
+            /* append value into array */
+            dbret = dbus_message_iter_append_basic(&it_values,
+                                                   DBUS_TYPE_STRING,
+                                                   &values[i]);
+            if (!dbret) {
+                ret = EIO;
+                goto done;
+            }
+        }
+
+        dbret = dbus_message_iter_close_container(&it_dict, &it_values);
+        if (!dbret) {
+            ret = EIO;
+            goto done;
+        }
+
+        dbret = dbus_message_iter_close_container(&it_array, &it_dict);
+        if (!dbret) {
+            ret = EIO;
+            goto done;
+        }
+    }
+
+    dbret = dbus_message_iter_close_container(iter, &it_array);
+    if (!dbret) {
+        ret = EIO;
+        goto done;
+    }
+
+done:
+    talloc_free(table_iter);
+    return ret;
+}
+
 void sbus_invoke_get(struct sbus_request *sbus_req,
                      const char *type,
                      sbus_get_invoker_fn invoker_fn,
diff --git a/src/sbus/sssd_dbus_invokers.h b/src/sbus/sssd_dbus_invokers.h
index 8fd49859489e79734e33d85bc03d19f8f1cb77ad..6f7f2540ee207a01b0081c8dbeb4fd15cbfa69fd 100644
--- a/src/sbus/sssd_dbus_invokers.h
+++ b/src/sbus/sssd_dbus_invokers.h
@@ -109,6 +109,10 @@ int sbus_invoke_get_ao(DBusMessageIter *iter,
                        struct sbus_request *sbus_req,
                        void *function_ptr);
 
+int sbus_invoke_get_aDOsasDE(DBusMessageIter *iter,
+                             struct sbus_request *sbus_req,
+                             void *function_ptr);
+
 void sbus_invoke_get(struct sbus_request *sbus_req,
                      const char *type,
                      sbus_get_invoker_fn invoker_fn,
diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c
index e0b4b1d1abf678042f25dbd7562f4ac958e982f4..9e9be52e84672eb3ee3afa4e13d5f60047150e98 100644
--- a/src/tests/sbus_codegen_tests.c
+++ b/src/tests/sbus_codegen_tests.c
@@ -539,6 +539,62 @@ void pilot_get_path_array_handler(struct sbus_request *dbus_req,
     array_getter_body(pilot_path_array, arr_out, arr_len);
 }
 
+void special_get_array_dict_sas(struct sbus_request *sbus_req,
+                                void *data,
+                                hash_table_t **_out)
+{
+    hash_table_t *table;
+    hash_key_t key;
+    hash_value_t value;
+    char **values;
+    errno_t ret;
+    int hret;
+
+    *_out = NULL;
+
+    ret = sss_hash_create(sbus_req, 10, &table);
+    ck_assert_int_eq(ret, EOK);
+
+    values = talloc_zero_array(table, char *, 3);
+    ck_assert(values != NULL);
+
+    values[0] = talloc_strdup(values, "hello1");
+    values[1] = talloc_strdup(values, "world1");
+
+    ck_assert(values[0] != NULL);
+    ck_assert(values[1] != NULL);
+
+    key.type = HASH_KEY_STRING;
+    key.str = talloc_strdup(table, "key1");
+
+    value.type = HASH_VALUE_PTR;
+    value.ptr = values;
+
+    hret = hash_enter(table, &key, &value);
+    ck_assert_int_eq(hret, HASH_SUCCESS);
+
+    values = talloc_zero_array(table, char *, 3);
+    ck_assert(values != NULL);
+
+    values[0] = talloc_strdup(values, "hello2");
+    values[1] = talloc_strdup(values, "world2");
+
+    ck_assert(values[0] != NULL);
+    ck_assert(values[1] != NULL);
+
+    key.type = HASH_KEY_STRING;
+    key.str = talloc_strdup(table, "key2");
+    ck_assert(key.str != NULL);
+
+    value.type = HASH_VALUE_PTR;
+    value.ptr = values;
+
+    hash_enter(table, &key, &value);
+    ck_assert_int_eq(hret, HASH_SUCCESS);
+
+    *_out = table;
+}
+
 struct test_pilot pilot_iface = {
     { &test_pilot_meta, 0 },
     .Eject = eject_handler,
@@ -570,6 +626,11 @@ struct test_pilot pilot_iface = {
     .get_object_path_array = pilot_get_path_array_handler,
 };
 
+struct test_special special_iface = {
+    { &test_special_meta, 0},
+    .get_array_dict_sas = special_get_array_dict_sas
+};
+
 static int pilot_test_server_init(struct sbus_connection *server, void *unused)
 {
     int ret;
@@ -581,6 +642,17 @@ static int pilot_test_server_init(struct sbus_connection *server, void *unused)
     return EOK;
 }
 
+static int special_test_server_init(struct sbus_connection *server, void *unused)
+{
+    int ret;
+
+    ret = sbus_conn_register_iface(server, &special_iface.vtable,
+                                   "/test/special", "Crash into the billboard");
+    ck_assert_int_eq(ret, EOK);
+
+    return EOK;
+}
+
 START_TEST(test_marshal_basic_types)
 {
     unsigned char arg_byte = 11;
@@ -1043,6 +1115,90 @@ START_TEST(test_get_basic_array_types)
 }
 END_TEST
 
+START_TEST(test_get_array_dict_sas)
+{
+    TALLOC_CTX *ctx;
+    DBusConnection *client;
+    DBusMessage *reply;
+    DBusMessageIter it_variant;
+    DBusMessageIter it_array;
+    DBusMessageIter it_dict;
+    DBusMessageIter it_dict_entry;
+    DBusMessageIter it_values;
+    DBusError error = DBUS_ERROR_INIT;
+    const char *prop = "array_dict_sas";
+    dbus_bool_t dbret;
+    const char *value;
+    const char *hash_content[2][2] = {{"hello1", "world1"},
+                                      {"hello2", "world2"}};
+    const char **exp_values;
+    int i;
+
+    ctx = talloc_new(NULL);
+    ck_assert(ctx != NULL);
+
+    client = test_dbus_setup_mock(ctx, NULL, special_test_server_init, NULL);
+    ck_assert(client != NULL);
+
+    reply = test_dbus_call_sync(client,
+                                "/test/special",
+                                DBUS_PROPERTIES_INTERFACE,
+                                "Get",
+                                &error,
+                                DBUS_TYPE_STRING, &test_special_meta.name,
+                                DBUS_TYPE_STRING, &prop,
+                                DBUS_TYPE_INVALID);
+    ck_assert(reply != NULL);
+
+    dbret = dbus_message_iter_init(reply, &it_variant);
+    ck_assert(dbret == TRUE);
+
+    ck_assert_int_eq(dbus_message_iter_get_arg_type(&it_variant), DBUS_TYPE_VARIANT);
+    dbus_message_iter_recurse(&it_variant, &it_array);
+
+    /* array */
+    ck_assert_int_eq(dbus_message_iter_get_arg_type(&it_array), DBUS_TYPE_ARRAY);
+    ck_assert_int_eq(dbus_message_iter_get_element_type(&it_array), DBUS_TYPE_DICT_ENTRY);
+
+    /* dict entry */
+
+    /* first item */
+    dbus_message_iter_recurse(&it_array, &it_dict);
+    for (i = 0; i < 2; i++) {
+        dbus_message_iter_recurse(&it_dict, &it_dict_entry);
+        ck_assert_int_eq(dbus_message_iter_get_arg_type(&it_dict_entry), DBUS_TYPE_STRING);
+
+        dbus_message_iter_get_basic(&it_dict_entry, &value);
+        ck_assert(value != NULL);
+        if (strcmp(value, "key1") == 0) {
+            exp_values = hash_content[0];
+        } else if (strcmp(value, "key2") == 0) {
+            exp_values = hash_content[1];
+        } else {
+            ck_abort_msg("Invalid key! %s", value);
+        }
+
+        dbret = dbus_message_iter_next(&it_dict_entry);
+        ck_assert(dbret == TRUE);
+
+        ck_assert_int_eq(dbus_message_iter_get_arg_type(&it_dict_entry), DBUS_TYPE_ARRAY);
+        ck_assert_int_eq(dbus_message_iter_get_element_type(&it_dict_entry), DBUS_TYPE_STRING);
+
+        dbus_message_iter_recurse(&it_dict_entry, &it_values);
+
+        dbus_message_iter_get_basic(&it_values, &value);
+        ck_assert(value != NULL);
+        ck_assert_str_eq(value, exp_values[0]);
+
+        dbret = dbus_message_iter_next(&it_values);
+        dbus_message_iter_get_basic(&it_values, &value);
+        ck_assert(value != NULL);
+        ck_assert_str_eq(value, exp_values[1]);
+        dbus_message_iter_next(&it_dict);
+    }
+}
+END_TEST
+
 struct prop_test {
     const char *name;
     bool handled;
@@ -1356,6 +1512,7 @@ TCase *create_handler_tests(void)
     tcase_add_test(tc, test_get_basic_types);
     tcase_add_test(tc, test_getall_basic_types);
     tcase_add_test(tc, test_get_basic_array_types);
+    tcase_add_test(tc, test_get_array_dict_sas);
 
     return tc;
 }
diff --git a/src/tests/sbus_codegen_tests.xml b/src/tests/sbus_codegen_tests.xml
index 90e27425414167f025c34da3ae5c06dc5a36f165..80eb421b9c1febed4304b0504a65cbe8d2f166fe 100755
--- a/src/tests/sbus_codegen_tests.xml
+++ b/src/tests/sbus_codegen_tests.xml
@@ -136,7 +136,15 @@
         <property name="double_array" type="ad" access="read"/>
         <property name="string_array" type="as" access="read"/>
         <property name="object_path_array" type="ao" access="read"/>
-
+    </interface>
+    
+    <!--
+      Special property types not suitable for group automatic tests.
+    -->
+    <interface name="com.planetexpress.Special">
+        <annotation value="test_special" name="org.freedesktop.DBus.GLib.CSymbol"/>
+        
+        <property name="array_dict_sas" type="a{sas}" access="read"/>
     </interface>
 
 </node>
diff --git a/src/tests/sbus_codegen_tests_generated.c b/src/tests/sbus_codegen_tests_generated.c
index fc69b77b347b9bec582aff633e26dbbe769985d5..3a5db43c5f277eafc37d11b10e011201aa8d8a69 100644
--- a/src/tests/sbus_codegen_tests_generated.c
+++ b/src/tests/sbus_codegen_tests_generated.c
@@ -463,6 +463,29 @@ const struct sbus_interface_meta test_pilot_meta = {
     sbus_invoke_get_all, /* GetAll invoker */
 };
 
+/* property info for com.planetexpress.Special */
+const struct sbus_property_meta test_special__properties[] = {
+    {
+        "array_dict_sas", /* name */
+        "a{sas}", /* type */
+        SBUS_PROPERTY_READABLE,
+        offsetof(struct test_special, get_array_dict_sas),
+        sbus_invoke_get_aDOsasDE,
+        0, /* not writable */
+        NULL, /* no invoker */
+    },
+    { NULL, }
+};
+
+/* interface info for com.planetexpress.Special */
+const struct sbus_interface_meta test_special_meta = {
+    "com.planetexpress.Special", /* name */
+    NULL, /* no methods */
+    NULL, /* no signals */
+    test_special__properties,
+    sbus_invoke_get_all, /* GetAll invoker */
+};
+
 /* invokes a handler with a 'bu' DBus signature */
 static int invoke_bu_method(struct sbus_request *dbus_req, void *function_ptr)
 {
diff --git a/src/tests/sbus_codegen_tests_generated.h b/src/tests/sbus_codegen_tests_generated.h
index d573615ecc1222a5b1e2c16d84d1ccb0514f58fd..27049cd3240887cadc2828167bbd70a13dde5b32 100644
--- a/src/tests/sbus_codegen_tests_generated.h
+++ b/src/tests/sbus_codegen_tests_generated.h
@@ -48,6 +48,10 @@
 #define TEST_PILOT_STRING_ARRAY "string_array"
 #define TEST_PILOT_OBJECT_PATH_ARRAY "object_path_array"
 
+/* constants for com.planetexpress.Special */
+#define TEST_SPECIAL "com.planetexpress.Special"
+#define TEST_SPECIAL_ARRAY_DICT_SAS "array_dict_sas"
+
 /* ------------------------------------------------------------------------
  * DBus handlers
  *
@@ -72,7 +76,7 @@ struct com_planetexpress_Ship {
     int (*MoveUniverse)(struct sbus_request *req, void *data, bool arg_smoothly, uint32_t arg_speed_factor);
     int (*crash_now)(struct sbus_request *req, void *data, const char *arg_where);
     sbus_msg_handler_fn Land;
-    void (*get_Color)(struct sbus_request *, void *data, const char * *);
+    void (*get_Color)(struct sbus_request *, void *data, const char **);
 };
 
 /* finish function for MoveUniverse */
@@ -86,30 +90,30 @@ struct test_pilot {
     struct sbus_vtable vtable; /* derive from sbus_vtable */
     int (*Blink)(struct sbus_request *req, void *data, uint32_t arg_duration);
     int (*Eject)(struct sbus_request *req, void *data, uint8_t arg_byte, bool arg_boolean, int16_t arg_int16, uint16_t arg_uint16, int32_t arg_int32, uint32_t arg_uint32, int64_t arg_int64, uint64_t arg_uint64, double arg_double, const char *arg_string, const char *arg_object_path, uint8_t arg_byte_array[], int len_byte_array, int16_t arg_int16_array[], int len_int16_array, uint16_t arg_uint16_array[], int len_uint16_array, int32_t arg_int32_array[], int len_int32_array, uint32_t arg_uint32_array[], int len_uint32_array, int64_t arg_int64_array[], int len_int64_array, uint64_t arg_uint64_array[], int len_uint64_array, double arg_double_array[], int len_double_array, const char *arg_string_array[], int len_string_array, const char *arg_object_path_array[], int len_object_path_array);
-    void (*get_FullName)(struct sbus_request *, void *data, const char * *);
-    void (*get_byte)(struct sbus_request *, void *data, uint8_t *);
-    void (*get_boolean)(struct sbus_request *, void *data, bool *);
-    void (*get_int16)(struct sbus_request *, void *data, int16_t *);
-    void (*get_uint16)(struct sbus_request *, void *data, uint16_t *);
-    void (*get_int32)(struct sbus_request *, void *data, int32_t *);
-    void (*get_uint32)(struct sbus_request *, void *data, uint32_t *);
-    void (*get_int64)(struct sbus_request *, void *data, int64_t *);
-    void (*get_uint64)(struct sbus_request *, void *data, uint64_t *);
-    void (*get_double)(struct sbus_request *, void *data, double *);
-    void (*get_string)(struct sbus_request *, void *data, const char * *);
-    void (*get_object_path)(struct sbus_request *, void *data, const char * *);
-    void (*get_null_string)(struct sbus_request *, void *data, const char * *);
-    void (*get_null_path)(struct sbus_request *, void *data, const char * *);
-    void (*get_byte_array)(struct sbus_request *, void *data, uint8_t * *, int *);
-    void (*get_int16_array)(struct sbus_request *, void *data, int16_t * *, int *);
-    void (*get_uint16_array)(struct sbus_request *, void *data, uint16_t * *, int *);
-    void (*get_int32_array)(struct sbus_request *, void *data, int32_t * *, int *);
-    void (*get_uint32_array)(struct sbus_request *, void *data, uint32_t * *, int *);
-    void (*get_int64_array)(struct sbus_request *, void *data, int64_t * *, int *);
-    void (*get_uint64_array)(struct sbus_request *, void *data, uint64_t * *, int *);
-    void (*get_double_array)(struct sbus_request *, void *data, double * *, int *);
-    void (*get_string_array)(struct sbus_request *, void *data, const char * * *, int *);
-    void (*get_object_path_array)(struct sbus_request *, void *data, const char * * *, int *);
+    void (*get_FullName)(struct sbus_request *, void *data, const char **);
+    void (*get_byte)(struct sbus_request *, void *data, uint8_t*);
+    void (*get_boolean)(struct sbus_request *, void *data, bool*);
+    void (*get_int16)(struct sbus_request *, void *data, int16_t*);
+    void (*get_uint16)(struct sbus_request *, void *data, uint16_t*);
+    void (*get_int32)(struct sbus_request *, void *data, int32_t*);
+    void (*get_uint32)(struct sbus_request *, void *data, uint32_t*);
+    void (*get_int64)(struct sbus_request *, void *data, int64_t*);
+    void (*get_uint64)(struct sbus_request *, void *data, uint64_t*);
+    void (*get_double)(struct sbus_request *, void *data, double*);
+    void (*get_string)(struct sbus_request *, void *data, const char **);
+    void (*get_object_path)(struct sbus_request *, void *data, const char **);
+    void (*get_null_string)(struct sbus_request *, void *data, const char **);
+    void (*get_null_path)(struct sbus_request *, void *data, const char **);
+    void (*get_byte_array)(struct sbus_request *, void *data, uint8_t**, int *);
+    void (*get_int16_array)(struct sbus_request *, void *data, int16_t**, int *);
+    void (*get_uint16_array)(struct sbus_request *, void *data, uint16_t**, int *);
+    void (*get_int32_array)(struct sbus_request *, void *data, int32_t**, int *);
+    void (*get_uint32_array)(struct sbus_request *, void *data, uint32_t**, int *);
+    void (*get_int64_array)(struct sbus_request *, void *data, int64_t**, int *);
+    void (*get_uint64_array)(struct sbus_request *, void *data, uint64_t**, int *);
+    void (*get_double_array)(struct sbus_request *, void *data, double**, int *);
+    void (*get_string_array)(struct sbus_request *, void *data, const char ***, int *);
+    void (*get_object_path_array)(struct sbus_request *, void *data, const char ***, int *);
 };
 
 /* finish function for Blink */
@@ -118,6 +122,12 @@ int test_pilot_Blink_finish(struct sbus_request *req, bool arg_crashed);
 /* finish function for Eject */
 int test_pilot_Eject_finish(struct sbus_request *req, uint8_t arg_byte, bool arg_boolean, int16_t arg_int16, uint16_t arg_uint16, int32_t arg_int32, uint32_t arg_uint32, int64_t arg_int64, uint64_t arg_uint64, double arg_double, const char *arg_string, const char *arg_object_path, uint8_t arg_byte_array[], int len_byte_array, int16_t arg_int16_array[], int len_int16_array, uint16_t arg_uint16_array[], int len_uint16_array, int32_t arg_int32_array[], int len_int32_array, uint32_t arg_uint32_array[], int len_uint32_array, int64_t arg_int64_array[], int len_int64_array, uint64_t arg_uint64_array[], int len_uint64_array, double arg_double_array[], int len_double_array, const char *arg_string_array[], int len_string_array, const char *arg_object_path_array[], int len_object_path_array);
 
+/* vtable for com.planetexpress.Special */
+struct test_special {
+    struct sbus_vtable vtable; /* derive from sbus_vtable */
+    void (*get_array_dict_sas)(struct sbus_request *, void *data, hash_table_t **);
+};
+
 /* ------------------------------------------------------------------------
  * DBus Interface Metadata
  *
@@ -134,4 +144,7 @@ extern const struct sbus_interface_meta com_planetexpress_Ship_meta;
 /* interface info for com.planetexpress.Pilot */
 extern const struct sbus_interface_meta test_pilot_meta;
 
+/* interface info for com.planetexpress.Special */
+extern const struct sbus_interface_meta test_special_meta;
+
 #endif /* __SBUS_CODEGEN_TESTS_XML__ */
-- 
2.1.0

