edbus: Parse EDBus_Message to Eina_Value
authorJosé Roberto de Souza <zehortigoza@profusion.mobi>
Fri, 26 Oct 2012 18:19:25 +0000 (18:19 +0000)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Fri, 26 Oct 2012 18:19:25 +0000 (18:19 +0000)
Patch by: José Roberto de Souza  <zehortigoza@profusion.mobi>

SVN revision: 78543

Makefile.am
src/lib/EDBus.h
src/lib/edbus_message_to_eina_value.c [new file with mode: 0644]
src/lib/edbus_message_to_eina_value.h [new file with mode: 0644]

index d22d988..ce14f77 100644 (file)
@@ -64,7 +64,8 @@ include_HEADERS = \
        src/lib/edbus_proxy.h \
        src/lib/edbus_service.h \
        src/lib/edbus_signal_handler.h \
-       src/lib/edbus_message_helper.h
+       src/lib/edbus_message_helper.h \
+       src/lib/edbus_message_to_eina_value.h
 
 libedbus2_la_LIBADD = @ECORE_LIBS@ @DBUS_LIBS@
 libedbus2_la_SOURCES = \
@@ -78,7 +79,8 @@ libedbus2_la_SOURCES = \
        src/lib/edbus_freedesktop.c \
        src/lib/edbus_service.c \
        src/lib/edbus_signal_handler.c \
-       src/lib/edbus_message_helper.c
+       src/lib/edbus_message_helper.c \
+       src/lib/edbus_message_to_eina_value.c
 
 if EFL_BUILD_EXAMPLES
 noinst_PROGRAMS = \
index 7fee3f3..4adfc62 100644 (file)
@@ -134,6 +134,7 @@ typedef void (*EDBus_Signal_Cb)(void *data, const EDBus_Message *msg);
 #include "edbus_freedesktop.h"
 #include "edbus_service.h"
 #include "edbus_message_helper.h"
+#include "edbus_message_to_eina_value.h"
 
 #ifdef __cplusplus
 }
diff --git a/src/lib/edbus_message_to_eina_value.c b/src/lib/edbus_message_to_eina_value.c
new file mode 100644 (file)
index 0000000..8a38745
--- /dev/null
@@ -0,0 +1,484 @@
+#include "edbus_private.h"
+#include "edbus_private_types.h"
+
+static void _message_iter_basic_array_to_eina_value(char type, Eina_Value *value, EDBus_Message_Iter *iter);
+static void _eina_value_struct_free(Eina_Value *value, Eina_Array *array);
+static Eina_Value *_message_iter_struct_to_eina_value(EDBus_Message_Iter *iter);
+
+static const Eina_Value_Type *
+_dbus_type_to_eina_value_type(char type)
+{
+   switch (type)
+     {
+      case 'i':
+      case 'h':
+         return EINA_VALUE_TYPE_INT;
+      case 's':
+      case 'o':
+      case 'g':
+         return EINA_VALUE_TYPE_STRING;
+      case 'b':
+      case 'y':
+         return EINA_VALUE_TYPE_UCHAR;
+      case 'n':
+         return EINA_VALUE_TYPE_SHORT;
+      case 'q':
+         return EINA_VALUE_TYPE_USHORT;
+      case 'u':
+         return EINA_VALUE_TYPE_UINT;
+      case 'x':
+         return EINA_VALUE_TYPE_INT64;
+      case 't':
+         return EINA_VALUE_TYPE_UINT64;
+      case 'd':
+         return EINA_VALUE_TYPE_DOUBLE;
+      case 'a':
+         return EINA_VALUE_TYPE_ARRAY;
+      case '(':
+      case '{':
+      case 'e':
+      case 'r':
+      case 'v':
+         return EINA_VALUE_TYPE_STRUCT;
+      default:
+         ERR("Unknown type %c", type);
+         return NULL;
+     }
+}
+
+static unsigned int
+_type_size(char type)
+{
+   switch (type)
+     {
+      case 'i':
+      case 'h':
+      case 'u':
+         return(sizeof(int32_t));
+      case 's':
+      case 'o':
+      case 'g':
+         return(sizeof(char *));
+      case 'b':
+      case 'y':
+         return(sizeof(unsigned char));
+      case 'n':
+      case 'q':
+         return(sizeof(int16_t));
+      case 'x':
+      case 't':
+         return(sizeof(int64_t));
+      case 'd':
+         return(sizeof(double));
+      case 'a':
+         return(sizeof(Eina_Value_Array));
+      case '(':
+      case '{':
+      case 'e':
+      case 'r':
+      case 'v':
+         return(sizeof(Eina_Value_Struct));
+      default:
+         ERR("Unknown type %c", type);
+         return 0;
+     }
+}
+
+static unsigned int
+_type_offset(char type, unsigned base)
+{
+   unsigned size, padding;
+   size = _type_size(type);
+   if (!(base % size))
+     return base;
+   padding = abs(base - size);
+   return base + padding;
+}
+
+static Eina_Value *
+_message_iter_array_to_eina_value(EDBus_Message_Iter *iter)
+{
+   Eina_Value *array_value;
+   char *sig;
+
+   sig = edbus_message_iter_signature_get(iter);
+   DBG("array of %s", sig);
+   array_value = eina_value_array_new(_dbus_type_to_eina_value_type(sig[0]), 0);
+   if (sig[0] == '(' || sig[0] == '{' || sig[0] == 'v')
+     {
+        EDBus_Message_Iter *entry;
+
+        if (sig[0] == '{')
+          sig[0] = 'e';
+        else if (sig[0] == '(')
+          sig[0] = 'r';
+
+        while (edbus_message_iter_get_and_next(iter, sig[0], &entry))
+          {
+             Eina_Value *data = _message_iter_struct_to_eina_value(entry);
+             Eina_Value_Struct st;
+             eina_value_get(data, &st);
+             eina_value_array_append(array_value, st);
+          }
+     }
+   else if (sig[0] == 'a')
+     {
+        EDBus_Message_Iter *entry;
+        while (edbus_message_iter_get_and_next(iter, sig[0], &entry))
+          {
+             Eina_Value *data = _message_iter_array_to_eina_value(entry);
+             Eina_Value_Array inner_array;
+             eina_value_get(data, &inner_array);
+             eina_value_array_append(array_value, inner_array);
+          }
+     }
+   else
+     _message_iter_basic_array_to_eina_value(sig[0], array_value, iter);
+
+   DBG("return array of %s", sig);
+   free(sig);
+   return array_value;
+}
+
+static void
+_message_iter_basic_array_to_eina_value(char type, Eina_Value *value, EDBus_Message_Iter *iter)
+{
+   switch (type)
+    {
+       case 'i':
+       case 'h'://fd
+         {
+            int32_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 's':
+       case 'o'://object path
+       case 'g'://signature
+         {
+            const char *txt;
+            while (edbus_message_iter_get_and_next(iter, type, &txt))
+              eina_value_array_append(value, txt);
+            break;
+         }
+       case 'b'://boolean
+       case 'y'://byte
+         {
+            unsigned char byte;
+            while (edbus_message_iter_get_and_next(iter, type, &byte))
+              eina_value_array_append(value, byte);
+            break;
+         }
+       case 'n'://int16
+         {
+            int16_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 'q'://uint16
+         {
+            uint16_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 'u'://uint32
+         {
+            uint32_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 'x'://int64
+         {
+            int64_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 't'://uint64
+         {
+            uint64_t i;
+            while (edbus_message_iter_get_and_next(iter, type, &i))
+              eina_value_array_append(value, i);
+            break;
+         }
+       case 'd'://double
+         {
+            double d;
+            while (edbus_message_iter_get_and_next(iter, type, &d))
+              eina_value_array_append(value, d);
+            break;
+         }
+    }
+}
+
+#define ARG "arg%d"
+
+static Eina_Value *
+_message_iter_struct_to_eina_value(EDBus_Message_Iter *iter)
+{
+   int type;
+   Eina_Value *value_st;
+   Eina_Array *st_members = eina_array_new(1);
+   unsigned int offset = 0, z;
+   static char name[7];//arg000 + \0
+   Eina_Value_Struct_Member *members;
+   Eina_Value_Struct_Desc *st_desc;
+   Eina_Array *st_values = eina_array_new(1);
+
+   DBG("begin struct");
+   st_desc = calloc(1, sizeof(Eina_Value_Struct_Desc));
+   st_desc->version = EINA_VALUE_STRUCT_DESC_VERSION;
+   st_desc->ops = NULL;
+
+   //create member list
+   z = 0;
+   while ((type = dbus_message_iter_get_arg_type(&iter->dbus_iterator)) != DBUS_TYPE_INVALID)
+     {
+        Eina_Value_Struct_Member *m;
+        Eina_Value *v;
+
+        m = calloc(1, sizeof(Eina_Value_Struct_Member));
+        sprintf(name, ARG, z);
+        m->name = strdup(name);
+        offset = _type_offset(type, offset);
+        m->offset = offset;
+        offset += _type_size(type);
+        m->type = _dbus_type_to_eina_value_type(type);
+        eina_array_push(st_members, m);
+
+        DBG("type = %c", type);
+        switch (type)
+          {
+           case 'i'://int
+           case 'h'://fd
+             {
+                int32_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_INT);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 's':
+           case 'o'://object path
+           case 'g'://signature
+             {
+                const char *txt;
+                v = eina_value_new(EINA_VALUE_TYPE_STRING);
+                edbus_message_iter_basic_get(iter, &txt);
+                eina_value_set(v, txt);
+                break;
+             }
+           case 'b'://boolean
+           case 'y'://byte
+             {
+                unsigned char byte;
+                v = eina_value_new(EINA_VALUE_TYPE_UCHAR);
+                edbus_message_iter_basic_get(iter, &byte);
+                eina_value_set(v, byte);
+                break;
+             }
+           case 'n'://int16
+             {
+                int16_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_SHORT);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 'q'://uint16
+             {
+                uint16_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_USHORT);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 'u'://uint32
+             {
+                uint32_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_UINT);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 'x'://int64
+             {
+                int64_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_INT64);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 't'://uint64
+             {
+                uint64_t i;
+                v = eina_value_new(EINA_VALUE_TYPE_UINT64);
+                edbus_message_iter_basic_get(iter, &i);
+                eina_value_set(v, i);
+                break;
+             }
+           case 'd'://double
+             {
+                double d;
+                v = eina_value_new(EINA_VALUE_TYPE_DOUBLE);
+                edbus_message_iter_basic_get(iter, &d);
+                eina_value_set(v, d);
+                break;
+             }
+           case 'a'://array
+             {
+                EDBus_Message_Iter *dbus_array;
+                dbus_array = edbus_message_iter_sub_iter_get(iter);
+                v = _message_iter_array_to_eina_value(dbus_array);
+                break;
+             }
+           case '('://struct
+           case 'r'://struct
+           case 'v'://variant
+             {
+                EDBus_Message_Iter *dbus_st;
+                dbus_st = edbus_message_iter_sub_iter_get(iter);
+                v = _message_iter_struct_to_eina_value(dbus_st);
+                break;
+             }
+           default:
+             ERR("Unexpected type %c", type);
+             v = NULL;
+          }
+        eina_array_push(st_values, v);
+        edbus_message_iter_next(iter);
+        z++;
+     }
+
+   members = malloc(eina_array_count(st_members) * sizeof(Eina_Value_Struct_Member));
+   for (z = 0; z < eina_array_count(st_members); z++)
+     {
+        Eina_Value_Struct_Member *m = eina_array_data_get(st_members, z);
+        members[z].name = m->name;
+        members[z].offset = m->offset;
+        members[z].type = m->type;
+        free(m);
+     }
+
+   //setup
+   st_desc->members = members;
+   st_desc->member_count = eina_array_count(st_members);
+   st_desc->size = offset;
+   value_st = eina_value_struct_new(st_desc);
+   eina_array_free(st_members);
+
+   //filling with data
+   for (z = 0; z < eina_array_count(st_values); z++)
+     {
+        Eina_Value *v = eina_array_data_get(st_values, z);
+        sprintf(name, ARG, z);
+        eina_value_struct_value_set(value_st, name, v);
+        eina_value_free(v);
+     }
+   eina_array_free(st_values);
+   DBG("end struct");
+   return value_st;
+}
+
+EAPI Eina_Value *
+edbus_message_to_eina_value(const EDBus_Message *msg)
+{
+   EDBus_Message_Iter *iter;
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(msg, NULL);
+   iter = edbus_message_iter_get(msg);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iter, NULL);
+   return _message_iter_struct_to_eina_value(iter);
+}
+
+static void
+_eina_value_array_free(Eina_Value *value, Eina_Array *array)
+{
+   Eina_Value_Array value_array;
+   unsigned i;
+
+   eina_value_pget(value, &value_array);
+   if (value_array.subtype == EINA_VALUE_TYPE_STRUCT)
+     {
+        for (i = 0; i < eina_value_array_count(value); i++)
+          {
+             Eina_Value st;
+             eina_value_array_value_get(value, i, &st);
+             _eina_value_struct_free(&st, array);
+             eina_value_flush(&st);
+          }
+     }
+   else if (value_array.subtype == EINA_VALUE_TYPE_ARRAY)
+     {
+        for (i = 0; i < eina_value_array_count(value); i++)
+          {
+             Eina_Value inner_array;
+             eina_value_array_value_get(value, i, &inner_array);
+             _eina_value_array_free(&inner_array, array);
+             eina_value_flush(&inner_array);
+          }
+     }
+}
+static void
+_eina_value_struct_free(Eina_Value *value, Eina_Array *array)
+{
+   Eina_Value_Struct st;
+   unsigned i;
+   static char name[7];
+
+   DBG("value %p", value);
+   EINA_SAFETY_ON_FALSE_RETURN(eina_value_pget(value, &st));
+
+   for (i = 0; i < st.desc->member_count; i++)
+     {
+        DBG("arg%d of %p", i, value);
+        if (st.desc->members[i].type == EINA_VALUE_TYPE_STRUCT)
+          {
+             Eina_Value sub;
+             sprintf(name, ARG, i);
+             eina_value_struct_value_get(value, name, &sub);
+             _eina_value_struct_free(&sub, array);
+             eina_value_flush(&sub);
+          }
+        else if (st.desc->members[i].type == EINA_VALUE_TYPE_ARRAY)
+          {
+             Eina_Value sub;
+             sprintf(name, ARG, i);
+             eina_value_struct_value_get(value, name, &sub);
+             _eina_value_array_free(&sub, array);
+             eina_value_flush(&sub);
+          }
+     }
+   eina_array_push(array, st.desc);
+   DBG("end value %p", value);
+}
+
+EAPI void
+edbus_message_to_eina_value_free(Eina_Value *value)
+{
+   Eina_Array *descriptions;
+   Eina_Value_Struct_Desc *st_desc;
+
+   EINA_SAFETY_ON_NULL_RETURN(value);
+   EINA_SAFETY_ON_FALSE_RETURN(eina_value_type_get(value) == EINA_VALUE_TYPE_STRUCT);
+
+   descriptions = eina_array_new(1);
+   _eina_value_struct_free(value, descriptions);
+   eina_value_free(value);
+
+   while ((st_desc = eina_array_pop(descriptions)))
+     {
+        unsigned i;
+        for (i = 0; i < st_desc->member_count; i++)
+          {
+             char *name = (char *)st_desc->members[i].name;
+             free(name);
+          }
+        free((Eina_Value_Struct_Member *)st_desc->members);
+        free(st_desc);
+     }
+   eina_array_free(descriptions);
+}
diff --git a/src/lib/edbus_message_to_eina_value.h b/src/lib/edbus_message_to_eina_value.h
new file mode 100644 (file)
index 0000000..b2e871d
--- /dev/null
@@ -0,0 +1,3 @@
+EAPI void edbus_message_to_eina_value_free(Eina_Value *value);
+
+EAPI Eina_Value *edbus_message_to_eina_value(const EDBus_Message *msg);