* eet: Add EET_G_VARIANT and EET_G_UNION.
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 21 Apr 2010 14:00:24 +0000 (14:00 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Wed, 21 Apr 2010 14:00:24 +0000 (14:00 +0000)
This are the basis for a new edje file format.
Next to come EET_G_INHERIT.

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eet@48201 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

ChangeLog
src/lib/Eet.h
src/lib/eet_data.c
src/lib/eet_dictionary.c
src/tests/eet_suite.c

index 3d7edc9..3c42e91 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
 2010-04-16  Cedric BAIL
 
        * Handle fixed point in data stream.
+
+2010-04-21  Cedric BAIL
+
+       * Add EET_G_UNION and EET_G_VARIANT.
index 41755da..627c565 100644 (file)
@@ -274,7 +274,7 @@ extern "C" {
     *
     * If the eet file handle is not valid nothing will be done.
     *
-    * @since 1.2.3
+    * @since 1.2.4
     * @ingroup Eet_File_Group
     */
    EAPI Eet_Error eet_sync(Eet_File *ef);
@@ -1491,7 +1491,10 @@ extern "C" {
 #define EET_G_VAR_ARRAY  102 /**< Variable size array group type */
 #define EET_G_LIST       103 /**< Linked list group type */
 #define EET_G_HASH       104 /**< Hash table group type */
-#define EET_G_LAST       105 /**< Last group type */
+#define EET_G_UNION      105 /**< Union group type */
+#define EET_G_INHERIT    106 /**< Inherit object group type */
+#define EET_G_VARIANT    107 /**< Selectable subtype group */
+#define EET_G_LAST       108 /**< Last group type */
 
 #define EET_I_LIMIT      128 /**< Other type exist but are reserved for internal purpose. */
 
@@ -1518,7 +1521,7 @@ extern "C" {
     * version member so it is compatible with abi changes, or at least
     * will not crash with them.
     */
-#define EET_DATA_DESCRIPTOR_CLASS_VERSION 2
+#define EET_DATA_DESCRIPTOR_CLASS_VERSION 3
 
   /**
    * @typedef Eet_Data_Descriptor_Class
@@ -1557,6 +1560,9 @@ extern "C" {
           void    (*hash_free) (void *h); /**< free all entries from the hash @p h */
            char   *(*str_direct_alloc) (const char *str); /**< how to allocate a string directly from file backed/mmaped region pointed by @p str */
            void    (*str_direct_free) (const char *str); /**< how to free a string returned by str_direct_alloc */
+
+          const char *(*type_get) (const void *data, Eina_Bool *unknow); /**< convert any kind of data type to a name that define an Eet_Data_Element. */
+          Eina_Bool  (*type_set) (const char *type, void *data, Eina_Bool unknow); /**< set the type at a particular adress */
        } func;
      };
 
@@ -2164,6 +2170,109 @@ extern "C" {
      }
 
    /**
+    * Add an union type to a data descriptor
+    * @param edd The data descriptor to add the type to.
+    * @param struct_type The type of the struct.
+    * @param name The string name to use to encode/decode this member
+    *        (must be a constant global and never change).
+    * @param member The struct member itself to be encoded.
+    * @param type_member The member that give hints on what is in the union.
+    * @param unified_type Describe all possible type the union could handle.
+    *
+    * This macro lets you easily add an union with a member that specify what is inside.
+    * The @p unified_type is an Eet_Data_Descriptor, but only the entry that match the name
+    * returned by type_get will be used for each serialized data. The type_get and type_set
+    * callback of unified_type should be defined.
+    *
+    * @since 1.2.4
+    * @ingroup Eet_Data_Group
+    * @see Eet_Data_Descriptor_Class
+    */
+#define EET_DATA_DESCRIPTOR_ADD_UNION(edd, struct_type, name, member, type_member, unified_type) \
+     { \
+        struct_type ___ett;                    \
+       \
+        eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_UNION, \
+                                        (char *) (&(___ett.member)) - (char *)(&(___ett)), \
+                                        (char *) (&(___ett.type_member)) - (char *)(&(___ett)), \
+                                       NULL, unified_type); \
+     }
+
+   /**
+    * Make a structure variable in size/content depend on it's type
+    * @param edd The data descriptor to add the type to.
+    * @param struct_type The type of the struct.
+    * @param name The string name to use to encode/decode this member
+    *        (must be a constant global and never change).
+    * @param member The struct member itself to be encoded.
+    * @param type_member The member that give hints on what is in the union.
+    * @param unified_type Describe all possible type the union could handle.
+    *
+    * This macro lets you easily add a switch for an object oriented representation. The position
+    * of the member that define the type must be fixed for all possible type. Eet will then choose
+    * in the unified_type the structure that need to be allocated to match the detected type.
+    * The type_get and type_set callback of unified_type should be defined. This should be the only
+    * type in edd.
+    *
+    * @since 1.2.4
+    * @ingroup Eet_Data_Group
+    * @see Eet_Data_Descriptor_Class
+    */
+#define EET_DATA_DESCRIPTOR_ADD_INHERIT(edd, struct_type, name, member, type_member, unified_type) \
+     { \
+        struct_type ___ett;                    \
+       \
+        eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_INHERIT, \
+                                        (char *) (&(___ett.member)) - (char *)(&(___ett)), \
+                                        (char *) (&(___ett.type_member)) - (char *)(&(___ett)), \
+                                       NULL, unified_type); \
+     }
+
+   /**
+    * Add a automatically selectable type to a data descriptor
+    * @param edd The data descriptor to add the type to.
+    * @param struct_type The type of the struct.
+    * @param name The string name to use to encode/decode this member
+    *        (must be a constant global and never change).
+    * @param member The struct member itself to be encoded.
+    * @param type_member The member that give hints on what is in the union.
+    * @param unified_type Describe all possible type the union could handle.
+    *
+    * This macro lets you easily define what the content of @p member points to depending of
+    * the content of @p type_member. The type_get and type_set callback of unified_type should
+    * be defined. If the the type is not know at the time of restoring it, eet will still call
+    * type_set of @p unified_type but the pointer will be set to a serialized binary representation
+    * of what eet know. This make it possible, to save this pointer again by just returning the string
+    * given previously and telling it by setting unknow to EINA_TRUE.
+    *
+    * @since 1.2.4
+    * @ingroup Eet_Data_Group
+    * @see Eet_Data_Descriptor_Class
+    */
+#define EET_DATA_DESCRIPTOR_ADD_VARIANT(edd, struct_type, name, member, type_member, unified_type) \
+     { \
+        struct_type ___ett;                    \
+       \
+        eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_VARIANT, \
+                                        (char *) (&(___ett.member)) - (char *)(&(___ett)), \
+                                        (char *) (&(___ett.type_member)) - (char *)(&(___ett)), \
+                                       NULL, unified_type); \
+     }
+
+   /**
+    * Add a mapping to a data descriptor that will be used by union, variant or inherited type
+    * @param unified_type The data descriptor to add the mapping to.
+    * @param name The string name to get/set type.
+    * @param subtype The matching data descriptor.
+    *
+    * @since 1.2.4
+    * @ingroup Eet_Data_Group
+    * @see Eet_Data_Descriptor_Class
+    */
+#define EET_DATA_DESCRIPTOR_ADD_MAPPING(unified_type, name, subtype) \
+  eet_data_descriptor_element_add(unified_type, name, EET_T_UNKNOW, EET_G_UNKNOWN, 0, 0, NULL, subtype);
+
+   /**
     * @defgroup Eet_Data_Cipher_Group Eet Data Serialization using A Ciphers
     *
     * Most of the @ref Eet_Data_Group have alternative versions that
index 7a3263e..45160ca 100644 (file)
@@ -74,6 +74,7 @@ typedef struct _Eet_Data_Descriptor_Hash    Eet_Data_Descriptor_Hash;
 typedef struct _Eet_Data_Encode_Hash_Info   Eet_Data_Encode_Hash_Info;
 typedef struct _Eet_Free                   Eet_Free;
 typedef struct _Eet_Free_Context           Eet_Free_Context;
+typedef struct _Eet_Variant_Unknow         Eet_Variant_Unknow;
 
 /*---*/
 
@@ -138,6 +139,8 @@ struct _Eet_Data_Descriptor
       void  (*hash_foreach) (void *h, int (*func) (void *h, const char *k, void *dt, void *fdt), void *fdt);
       void *(*hash_add) (void *h, const char *k, void *d);
       void  (*hash_free) (void *h);
+      const char *(*type_get) (const void *data, Eina_Bool *unknow);
+      Eina_Bool (*type_set) (const char *type, void *data, Eina_Bool unknow);
    } func;
    struct {
       int                num;
@@ -147,6 +150,8 @@ struct _Eet_Data_Descriptor
         Eet_Data_Descriptor_Hash       *buckets;
       } hash;
    } elements;
+
+   Eina_Bool unified_type : 1;
 //   char *strings;
 //   int   strings_len;
 };
@@ -188,6 +193,14 @@ struct _Eet_Free_Context
    Eet_Free freelist_direct_str;
 };
 
+struct _Eet_Variant_Unknow
+{
+   EINA_MAGIC;
+
+   int size;
+   char data[1];
+};
+
 /*---*/
 
 static int   eet_data_get_char(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest);
@@ -228,6 +241,12 @@ static int  eet_data_get_list(Eet_Free_Context *context, const Eet_Dictionary *e
 static void eet_data_put_list(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in);
 static void eet_data_put_hash(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in);
 static int  eet_data_get_hash(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, char **p, int *size);
+static void eet_data_put_union(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in);
+static int  eet_data_get_union(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, char **p, int *size);
+static void eet_data_put_inherit(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in);
+static int  eet_data_get_inherit(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, char **p, int *size);
+static void eet_data_put_variant(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in);
+static int  eet_data_get_variant(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, char **p, int *size);
 
 static void            eet_data_chunk_get(const Eet_Dictionary *ed, Eet_Data_Chunk *chnk, const void *src, int size);
 static Eet_Data_Chunk *eet_data_chunk_new(void *data, int size, const char *name, int type, int group_type);
@@ -275,7 +294,10 @@ static const Eet_Data_Group_Type_Codec eet_group_codec[] =
      { eet_data_get_array,    eet_data_put_array },
      { eet_data_get_array,    eet_data_put_array },
      { eet_data_get_list,     eet_data_put_list },
-     { eet_data_get_hash,     eet_data_put_hash }
+     { eet_data_get_hash,     eet_data_put_hash },
+     { eet_data_get_union,    eet_data_put_union },
+     { eet_data_get_inherit,  eet_data_put_inherit },
+     { eet_data_get_variant,  eet_data_put_variant }
 };
 
 static int _eet_data_words_bigendian = -1;
@@ -325,6 +347,7 @@ static int _eet_data_words_bigendian = -1;
 #define EET_I_INLINED_STRING   2 << 4
 #define EET_I_NULL             3 << 4
 
+#define EET_MAGIC_VARIANT 0xF1234BC
 /*---*/
 
 /* CHAR TYPE */
@@ -1305,7 +1328,6 @@ _eet_data_descriptor_new(const Eet_Data_Descriptor_Class *eddc, int version)
    Eet_Data_Descriptor *edd;
 
    if (!eddc) return NULL;
-   if (eddc->version < version) return NULL;
 
    edd = calloc(1, sizeof (Eet_Data_Descriptor));
    if (!edd) return NULL;
@@ -1333,11 +1355,16 @@ _eet_data_descriptor_new(const Eet_Data_Descriptor_Class *eddc, int version)
    edd->func.hash_add = eddc->func.hash_add;
    edd->func.hash_free = eddc->func.hash_free;
 
-   if (version > 1)
+   if (eddc->version > 1 && version > 1)
      {
        edd->func.str_direct_alloc = eddc->func.str_direct_alloc;
        edd->func.str_direct_free = eddc->func.str_direct_free;
      }
+   if (eddc->version > 2)
+     {
+       edd->func.type_get = eddc->func.type_get;
+       edd->func.type_set = eddc->func.type_set;
+     }
 
    return edd;
 }
@@ -1421,6 +1448,43 @@ eet_data_descriptor_element_add(Eet_Data_Descriptor *edd,
    Eet_Data_Element *ede;
    Eet_Data_Element *tmp;
 
+   /* UNION, INHERITED or VARIANT type would not work with simple type, we need a way to map the type. */
+   if ((group_type == EET_G_INHERIT
+       || group_type == EET_G_UNION
+       || group_type == EET_G_VARIANT)
+       &&
+       (type != EET_T_UNKNOW
+       || subtype == NULL
+       || subtype->func.type_get == NULL
+       || subtype->func.type_set == NULL))
+     return ;
+
+   /* Only one element is allowed with INHERITED type */
+   if (group_type == EET_G_INHERIT && edd->elements.num != 0)
+     return ;
+   if (edd->elements.num > 0 && edd->elements.set[0].group_type == EET_G_INHERIT)
+     return ;
+
+   /* VARIANT type will only work if the map only contains EET_G_*, but not INHERIT, UNION, VARIANT and ARRAY. */
+   if (group_type == EET_G_VARIANT)
+     {
+       int i;
+
+       for (i = 0; i < subtype->elements.num; ++i)
+         if (subtype->elements.set[i].type != EET_T_UNKNOW
+             && subtype->elements.set[i].group_type > EET_G_VAR_ARRAY
+             && subtype->elements.set[i].group_type < EET_G_UNION)
+           return ;
+
+       subtype->unified_type = EINA_TRUE;
+     }
+   if (subtype
+       && subtype->unified_type
+       && (type != EET_T_UNKNOW
+          || group_type < EET_G_UNION))
+     return ;
+
+   /* Sanity check done, let allocate ! */
    edd->elements.num++;
    tmp = realloc(edd->elements.set, edd->elements.num * sizeof(Eet_Data_Element));
    if (!tmp) return ;
@@ -1455,7 +1519,7 @@ eet_data_descriptor_element_add(Eet_Data_Descriptor *edd,
    ede->group_type = group_type;
    ede->offset = offset;
    ede->count = count;
-   /* FIXME: For the time being, EET_G_VAR_ARRAY will put the counter_offset in count. */
+   /* FIXME: For the time being, VAR_ARRAY, INHERIT, UNION and VARIANT  will put the counter_offset in count. */
    ede->counter_offset = count;
 /*    ede->counter_offset = counter_offset; */
    ede->counter_name = counter_name;
@@ -2440,12 +2504,14 @@ _eet_data_descriptor_decode(Eet_Free_Context *context,
              break;
           case EET_G_VAR_ARRAY:
              return eet_node_var_array_new(chnk.name, NULL);
-          case EET_G_LIST:
+          case EET_G_INHERIT:
+             /* This one should work */
              goto error;
+          case EET_G_LIST:
           case EET_G_HASH:
-             goto error;
           case EET_G_ARRAY:
-             goto error;
+          case EET_G_UNION:
+          case EET_G_VARIANT:
           default:
              goto error;
          }
@@ -2818,6 +2884,379 @@ eet_data_get_array(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data
    return 0;
 }
 
+static void
+eet_data_put_union(Eet_Dictionary *ed,
+                  __UNUSED__ Eet_Data_Descriptor *edd,
+                  Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in)
+{
+   const char *union_type;
+   int i;
+
+   EET_ASSERT(!((ede->type != EET_T_UNKNOW) || (!ede->subtype)), return );
+
+   union_type = ede->subtype->func.type_get(((char*) data_in) + ede->count - ede->offset,
+                                           NULL);
+
+   if (!union_type) return ;
+
+   /* Search the structure of the union to encode. */
+   for (i = 0; i < ede->subtype->elements.num; ++i)
+     if (strcmp(ede->subtype->elements.set[i].name, union_type) == 0)
+       {
+         Eet_Data_Element *sede;
+         void *data;
+         int size;
+
+         /* Yeah we found it ! */
+         data = eet_data_put_type(ed, EET_T_STRING, &union_type, &size);
+         if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type);
+
+         sede = &(ede->subtype->elements.set[i]);
+         data = _eet_data_descriptor_encode(ed,
+                                            sede->subtype,
+                                            data_in,
+                                            &size);
+         if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type);
+         break;
+       }
+}
+
+static int
+eet_data_get_union(Eet_Free_Context *context, const Eet_Dictionary *ed,
+                  __UNUSED__ Eet_Data_Descriptor *edd,
+                  Eet_Data_Element *ede, Eet_Data_Chunk *echnk,
+                  int type, int group_type, void *data,
+                  char **p, int *size)
+{
+   const char *union_type;
+   void *data_ret = NULL;
+   int ret = 0;
+   int i;
+
+   /* Read type */
+   ret = eet_data_get_type(ed,
+                          EET_T_STRING,
+                          echnk->data,
+                          ((char *)echnk->data) + echnk->size,
+                          &union_type);
+   if (ret <= 0) goto on_error;
+
+   /* Advance to next chunk */
+   NEXT_CHUNK((*p), (*size), (*echnk), ed);
+   memset(echnk, 0, sizeof(Eet_Data_Chunk));
+
+   /* Read value */
+   eet_data_chunk_get(ed, echnk, *p, *size);
+   if (!echnk->name) goto on_error;
+
+   if (ede)
+     {
+       EET_ASSERT(!(ede->group_type != group_type || ede->type != type), goto on_error);
+
+       /* Search the structure of the union to decode */
+       for (i = 0; i < ede->subtype->elements.num; ++i)
+         if (strcmp(ede->subtype->elements.set[i].name, union_type) == 0)
+           {
+              Eet_Data_Element *sede;
+
+              /* Yeah we found it ! */
+              sede = &(ede->subtype->elements.set[i]);
+              EET_ASSERT(sede->subtype, goto on_error);
+
+              data_ret = _eet_data_descriptor_decode(context,
+                                                     ed,
+                                                     sede->subtype,
+                                                     echnk->data,
+                                                     echnk->size);
+              if (!data_ret) goto on_error;
+
+              /* Memcopy the structure content to remove pointer indirection. */
+              memcpy(data, data_ret, sede->subtype->size);
+
+              /* data_ret is now useless. */
+              sede->subtype->func.mem_free(data_ret);
+
+              /* Set union type. */
+              if ((!ed) || (!ede->subtype->func.str_direct_alloc))
+                {
+                   union_type = ede->subtype->func.str_alloc(union_type);
+                   _eet_freelist_str_add(context, (char*) union_type);
+                }
+              else
+                {
+                   union_type = ede->subtype->func.str_direct_alloc(union_type);
+                   _eet_freelist_direct_str_add(context, (char*) union_type);
+                }
+
+              ede->subtype->func.type_set(union_type,
+                                          ((char*) data) + ede->count - ede->offset,
+                                          EINA_FALSE);
+
+              break;
+           }
+     }
+   else
+     {
+       /* FIXME: generate node structure. */
+       data_ret = _eet_data_descriptor_decode(context,
+                                              ed, NULL,
+                                              echnk->data, echnk->size);
+       goto on_error;
+     }
+
+   return 1;
+
+ on_error:
+   return 0;
+}
+
+static void
+eet_data_put_inherit(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede,
+                    Eet_Data_Stream *ds, void *data_in)
+{
+   /* FIXME */
+   fprintf(stderr, "wrong !!!\n");
+}
+
+static int
+eet_data_get_inherit(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd,
+                    Eet_Data_Element *ede, Eet_Data_Chunk *echnk,
+                    int type, int group_type, void *data,
+                    char **p, int *size)
+{
+   /* FIXME */
+   return 0;
+}
+
+static void
+eet_data_put_variant(Eet_Dictionary *ed,
+                    __UNUSED__ Eet_Data_Descriptor *edd,
+                    Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in)
+{
+   const char *union_type;
+   void *data;
+   Eina_Bool unknow = EINA_FALSE;
+   int size;
+   int i;
+
+   EET_ASSERT(!((ede->type != EET_T_UNKNOW) || (!ede->subtype)), return );
+
+   union_type = ede->subtype->func.type_get(((char*) data_in) + ede->count - ede->offset,
+                                           &unknow);
+
+   if (!union_type && unknow == EINA_FALSE) return ;
+
+   if (unknow)
+     {
+       /* Handle opaque internal representation */
+       Eet_Variant_Unknow *evu;
+
+       data = eet_data_put_type(ed, EET_T_STRING, &union_type, &size);
+       if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type);
+
+       evu = (Eet_Variant_Unknow*) data_in;
+       if (evu && EINA_MAGIC_CHECK(evu, EET_MAGIC_VARIANT))
+         eet_data_encode(ed, ds, evu->data, ede->name, evu->size, ede->type, ede->group_type);
+     }
+   else
+     {
+       /* Search the structure of the union to encode. */
+       for (i = 0; i < ede->subtype->elements.num; ++i)
+         if (strcmp(ede->subtype->elements.set[i].name, union_type) == 0)
+           {
+              Eet_Data_Element *sede;
+
+              /* Yeah we found it ! */
+              data = eet_data_put_type(ed, EET_T_STRING, &union_type, &size);
+              if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type);
+
+              sede = &(ede->subtype->elements.set[i]);
+
+              if (sede->group_type != EET_G_UNKNOWN)
+                {
+                   Eet_Data_Stream *lds;
+
+                   lds = eet_data_stream_new();
+                   eet_group_codec[sede->group_type - 100].put(ed,
+                                                               sede->subtype,
+                                                               sede,
+                                                               lds,
+                                                               data_in);
+                   if (lds->size != 0)
+                     {
+                        eet_data_encode(ed, ds, lds->data, ede->name, lds->pos,
+                                        ede->type, ede->group_type);
+
+                        lds->data = NULL;
+                        lds->size = 0;
+                     }
+                   else
+                     {
+                        eet_data_encode(ed, ds, NULL, ede->name, 0,
+                                        EET_T_NULL, ede->group_type);
+                     }
+
+                   eet_data_stream_free(lds);
+                }
+              else
+                {
+                   data = _eet_data_descriptor_encode(ed,
+                                                      sede->subtype,
+                                                      *(void**)data_in,
+                                                      &size);
+                   if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type);
+                }
+
+              break;
+           }
+     }
+}
+
+static int
+eet_data_get_variant(Eet_Free_Context *context, const Eet_Dictionary *ed,
+                    __UNUSED__ Eet_Data_Descriptor *edd,
+                    Eet_Data_Element *ede, Eet_Data_Chunk *echnk,
+                    int type, int group_type, void *data,
+                    char **p, int *size)
+{
+   const char *union_type;
+   void *data_ret = NULL;
+   int ret = 0;
+   int i;
+
+   /* Read type */
+   ret = eet_data_get_type(ed,
+                          EET_T_STRING,
+                          echnk->data,
+                          ((char *)echnk->data) + echnk->size,
+                          &union_type);
+   if (ret <= 0) goto on_error;
+
+   /* Advance to next chunk */
+   NEXT_CHUNK((*p), (*size), (*echnk), ed);
+   memset(echnk, 0, sizeof(Eet_Data_Chunk));
+
+   /* Read value */
+   eet_data_chunk_get(ed, echnk, *p, *size);
+   if (!echnk->name) goto on_error;
+
+   if (ede)
+     {
+       EET_ASSERT(ede->subtype, goto on_error);
+
+       if ((!ed) || (!ede->subtype->func.str_direct_alloc))
+         {
+            union_type = ede->subtype->func.str_alloc(union_type);
+            _eet_freelist_str_add(context, (char*) union_type);
+         }
+       else
+         {
+            union_type = ede->subtype->func.str_direct_alloc(union_type);
+            _eet_freelist_direct_str_add(context, (char*) union_type);
+         }
+
+       /* Search the structure of the union to decode */
+       for (i = 0; i < ede->subtype->elements.num; ++i)
+         if (strcmp(ede->subtype->elements.set[i].name, union_type) == 0)
+           {
+              Eet_Data_Element *sede;
+
+              /* Yeah we found it ! */
+              sede = &(ede->subtype->elements.set[i]);
+
+              if (sede->group_type != EET_G_UNKNOWN)
+                {
+                   Eet_Data_Chunk chnk;
+                   char *p2;
+                   int size2;
+                   int ret;
+
+                   p2 = echnk->data;
+                   size2 = echnk->size;
+
+                   /* Didn't find a proper way to provide this
+                      without duplicating code */
+                   while (size2 > 0)
+                     {
+                        memset(&chnk, 0, sizeof(Eet_Data_Chunk));
+                        eet_data_chunk_get(ed, &chnk, p2, size2);
+
+                        if (!chnk.name) goto on_error;
+
+                        ret = eet_group_codec[sede->group_type - 100].get(context,
+                                                                          ed, sede->subtype,
+                                                                          sede, &chnk,
+                                                                          sede->type, sede->group_type,
+                                                                          data, &p2, &size2);
+
+                        if (ret <= 0) goto on_error;
+
+                        /* advance to next chunk */
+                        NEXT_CHUNK(p2, size2, chnk, ed);
+                     }
+
+                   /* Put garbage so that we will not put eet_variant_unknow in it */
+                   data_ret = (void*) data;
+
+                   /* Set variant type. */
+                   ede->subtype->func.type_set(union_type,
+                                               ((char*) data) + ede->count - ede->offset,
+                                               EINA_FALSE);
+                   break;
+                }
+
+              data_ret = _eet_data_descriptor_decode(context,
+                                                     ed,
+                                                     sede->subtype,
+                                                     echnk->data,
+                                                     echnk->size);
+              if (!data_ret) break;
+
+              /* And point to the variant data. */
+              *(void**) data = data_ret;
+
+              /* Set variant type. */
+              ede->subtype->func.type_set(union_type,
+                                          ((char*) data) + ede->count - ede->offset,
+                                          EINA_FALSE);
+              break;
+           }
+
+       if (!data_ret)
+         {
+            Eet_Variant_Unknow *evu;
+
+            evu = calloc(1, sizeof (Eet_Variant_Unknow) + echnk->size - 1);
+            if (!evu) goto on_error;
+
+            evu->size = echnk->size;
+            memcpy(evu->data, echnk->data, evu->size);
+            EINA_MAGIC_SET(evu, EET_MAGIC_VARIANT);
+
+            /* And point to the opaque internal data scructure */
+            *(void**) data = evu;
+
+            /* Set variant type. */
+            ede->subtype->func.type_set(union_type,
+                                        ((char*) data) + ede->count - ede->offset,
+                                        EINA_TRUE);
+         }
+     }
+   else
+     {
+       /* FIXME: dump node structure. */
+       data_ret = _eet_data_descriptor_decode(context,
+                                              ed, NULL,
+                                              echnk->data, echnk->size);
+       goto on_error;
+     }
+
+   return 1;
+
+ on_error:
+   return 0;
+}
+
 static Eet_Node *
 eet_data_node_simple_type(int type, const char *name, void *dd)
 {
index 42dbd1b..7ccd184 100644 (file)
@@ -325,7 +325,7 @@ eet_dictionary_string_get_fp(const Eet_Dictionary *ed, int idx, Eina_F32p32 *res
 
        str = ed->all[idx].str ? ed->all[idx].str : ed->all[idx].mmap;
 
-       if (!eina_convert_atofp(str,  ed->all[idx].len, &fp))
+       if (!eina_convert_atofp(str, ed->all[idx].len, &fp))
          return EINA_FALSE;
 
        ed->all[idx].fp = fp;
index 5f46d74..d138e25 100644 (file)
@@ -1756,6 +1756,430 @@ START_TEST(eet_file_fp)
 }
 END_TEST
 
+typedef struct _Eet_Union_Test Eet_Union_Test;
+typedef struct _Eet_Variant_Test Eet_Variant_Test;
+typedef struct _Eet_Variant_Type Eet_Variant_Type;
+typedef struct _Eet_Inherit_Test1 Eet_Inherit_Test1;
+typedef struct _Eet_Inherit_Test2 Eet_Inherit_Test2;
+typedef struct _Eet_Inherit_Test3 Eet_Inherit_Test3;
+typedef struct _Eet_St1 Eet_St1;
+typedef struct _Eet_St2 Eet_St2;
+typedef struct _Eet_St3 Eet_St3;
+typedef struct _Eet_List Eet_List;
+
+typedef enum _Eet_Union
+{
+  EET_UNKNOWN,
+  EET_ST1,
+  EET_ST2,
+  EET_ST3
+} Eet_Union;
+
+struct {
+   Eet_Union u;
+   const char *name;
+} eet_mapping[] = {
+  { EET_ST1, "ST1" },
+  { EET_ST2, "ST2" },
+  { EET_ST3, "ST3" },
+  { EET_UNKNOWN, NULL }
+};
+
+struct _Eet_St1
+{
+   double val1;
+   int stuff;
+   char *s1;
+};
+
+struct _Eet_St2
+{
+   Eina_Bool b1;
+   unsigned long long v1;
+};
+
+struct _Eet_St3
+{
+   int boby;
+};
+
+struct _Eet_Union_Test
+{
+   Eet_Union type;
+
+   union {
+      Eet_St1 st1;
+      Eet_St2 st2;
+      Eet_St3 st3;
+   } u;
+};
+
+struct _Eet_Variant_Type
+{
+   const char *type;
+   Eina_Bool unknow : 1;
+};
+
+struct _Eet_Variant_Test
+{
+   Eet_Variant_Type t;
+
+   void *data;
+   Eina_List *data_list;
+};
+
+struct _Eet_Inherit_Test1
+{
+   Eet_Union type;
+   Eet_St1 st1;
+};
+struct _Eet_Inherit_Test2
+{
+   Eet_Union type;
+   Eet_St2 st2;
+};
+struct _Eet_Inherit_Test3
+{
+   Eet_Union type;
+   Eet_St3 st3;
+};
+
+struct _Eet_List
+{
+   Eina_List *list;
+};
+
+static const char *
+_eet_union_type_get(const void *data, Eina_Bool *unknow)
+{
+   const Eet_Union *u = data;
+   int i;
+
+   if (unknow) *unknow = EINA_FALSE;
+   for (i = 0; eet_mapping[i].name != NULL; ++i)
+     if (*u == eet_mapping[i].u)
+       return eet_mapping[i].name;
+
+   if (unknow) *unknow = EINA_TRUE;
+   return NULL;
+}
+
+static Eina_Bool
+_eet_union_type_set(const char *type, void *data, Eina_Bool unknow)
+{
+   Eet_Union *u = data;
+   int i;
+
+   if (unknow) return EINA_FALSE;
+
+   for (i = 0; eet_mapping[i].name != NULL; ++i)
+     if (strcmp(eet_mapping[i].name, type) == 0)
+       {
+         *u = eet_mapping[i].u;
+         return EINA_TRUE;
+       }
+
+   return EINA_FALSE;
+}
+
+static const char *
+_eet_variant_type_get(const void *data, Eina_Bool *unknow)
+{
+   const Eet_Variant_Type *type = data;
+   int i;
+
+   if (unknow) *unknow = type->unknow;
+   for (i = 0; eet_mapping[i].name != NULL; ++i)
+     if (strcmp(type->type, eet_mapping[i].name) == 0)
+       return eet_mapping[i].name;
+
+   if (unknow) *unknow = EINA_FALSE;
+   return type->type;
+}
+
+static Eina_Bool
+_eet_variant_type_set(const char *type, void *data, Eina_Bool unknow)
+{
+   Eet_Variant_Type *vt = data;
+
+   vt->type = type;
+   vt->unknow = unknow;
+   return EINA_TRUE;
+}
+
+static Eet_Data_Descriptor*
+_eet_st1_dd(void)
+{
+   Eet_Data_Descriptor_Class eddc;
+   Eet_Data_Descriptor *res;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_St1);
+   res = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St1, "val1", val1, EET_T_DOUBLE);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St1, "stuff", stuff, EET_T_INT);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St1, "s1", s1, EET_T_STRING);
+
+   return res;
+}
+
+static void
+_eet_st1_set(Eet_St1 *st1, int i)
+{
+   st1->val1 = EET_TEST_DOUBLE;
+   st1->stuff = EET_TEST_INT + i;
+   st1->s1 = EET_TEST_STRING;
+}
+
+static void
+_eet_st1_cmp(Eet_St1 *st1, int i)
+{
+   double tmp;
+
+   fail_if(!st1);
+
+   tmp = st1->val1 - EET_TEST_DOUBLE;
+   if (tmp < 0) tmp = -tmp;
+   fail_if(tmp > 0.005);
+   fail_if(st1->stuff != EET_TEST_INT + i);
+   fail_if(strcmp(st1->s1, EET_TEST_STRING));
+}
+
+static Eet_Data_Descriptor*
+_eet_st2_dd(void)
+{
+   Eet_Data_Descriptor_Class eddc;
+   Eet_Data_Descriptor *res;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_St2);
+   res = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St2, "b1", b1, EET_T_UCHAR);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St2, "v1", v1, EET_T_ULONG_LONG);
+
+   return res;
+}
+
+static void
+_eet_st2_set(Eet_St2 *st2, int i)
+{
+   st2->b1 = EINA_TRUE;
+   st2->v1 = EET_TEST_LONG_LONG + i;
+}
+
+static void
+_eet_st2_cmp(Eet_St2 *st2, int i)
+{
+   fail_if(!st2->b1);
+   fail_if(st2->v1 != EET_TEST_LONG_LONG + i);
+}
+
+static Eet_Data_Descriptor*
+_eet_st3_dd(void)
+{
+   Eet_Data_Descriptor_Class eddc;
+   Eet_Data_Descriptor *res;
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_St3);
+   res = eet_data_descriptor_stream_new(&eddc);
+   EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St3, "boby", boby, EET_T_INT);
+
+   return res;
+}
+
+static void
+_eet_st3_set(Eet_St3 *st3, int i)
+{
+   st3->boby = EET_TEST_INT + i;
+}
+
+static void
+_eet_st3_cmp(Eet_St3 *st3, int i)
+{
+   fail_if(st3->boby != EET_TEST_INT + i);
+}
+
+START_TEST(eet_test_union)
+{
+   Eet_Union_Test *eut;
+   Eet_List *l;
+   Eet_Data_Descriptor_Class eddc;
+   Eet_Data_Descriptor *edd;
+   Eet_Data_Descriptor *unified;
+   Eet_Data_Descriptor *m;
+   void *blob;
+   int size;
+   int i;
+
+   eina_init();
+   eet_init();
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_Union_Test);
+   edd = eet_data_descriptor_stream_new(&eddc);
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_Union_Test);
+   m = eet_data_descriptor_stream_new(&eddc);
+
+   eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION;
+   eddc.func.type_get = _eet_union_type_get;
+   eddc.func.type_set = _eet_union_type_set;
+   unified = eet_data_descriptor_stream_new(&eddc);
+
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST1", _eet_st1_dd());
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST2", _eet_st2_dd());
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST3", _eet_st3_dd());
+
+   EET_DATA_DESCRIPTOR_ADD_UNION(edd, Eet_Union_Test, "u", u, type, unified);
+
+   EET_DATA_DESCRIPTOR_ADD_LIST(m, Eet_List, "list", list, edd);
+
+   l = calloc(1, sizeof (Eet_List));
+
+#define EUT_NEW(Type_Index)                    \
+   eut = calloc(1, sizeof (Eet_Union_Test));   \
+   eut->type = EET_ST##Type_Index;             \
+   _eet_st##Type_Index##_set(&(eut->u.st##Type_Index), i);
+
+   for (i = 0; i < 3; ++i)
+     {
+       EUT_NEW(1);
+       l->list = eina_list_append(l->list, eut);
+
+       EUT_NEW(2);
+       l->list = eina_list_append(l->list, eut);
+
+       EUT_NEW(3);
+       l->list = eina_list_append(l->list, eut);
+     }
+
+   blob = eet_data_descriptor_encode(m, l, &size);
+   fail_if(!blob || size <= 0);
+
+   l = eet_data_descriptor_decode(m, blob, size);
+   fail_if(!l);
+
+   fail_if(eina_list_count(l->list) != 9);
+
+#define EUT_CMP(Type_Index)                                    \
+   eut = eina_list_nth(l->list, i * 3 + Type_Index - 1);       \
+   fail_if(eut->type != EET_ST##Type_Index);                   \
+   _eet_st##Type_Index##_cmp(&(eut->u.st##Type_Index), i);
+
+   for (i = 0; i < 3; ++i)
+     {
+       EUT_CMP(1);
+       EUT_CMP(2);
+       EUT_CMP(3);
+     }
+
+   eet_shutdown();
+   eina_shutdown();
+}
+END_TEST
+
+START_TEST(eet_test_variant)
+{
+   Eet_Variant_Test *evt;
+   Eet_List *l;
+   Eet_St1 *st1;
+   Eet_St2 *st2;
+   Eet_St3 *st3;
+   Eet_Data_Descriptor_Class eddc;
+   Eet_Data_Descriptor *edd;
+   Eet_Data_Descriptor *unified;
+   Eet_Data_Descriptor *m;
+   void *blob;
+   int size;
+   int i;
+
+   eina_init();
+   eet_init();
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_Variant_Test);
+   edd = eet_data_descriptor_stream_new(&eddc);
+
+   EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_Variant_Test);
+   m = eet_data_descriptor_stream_new(&eddc);
+
+   eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION;
+   eddc.func.type_get = _eet_variant_type_get;
+   eddc.func.type_set = _eet_variant_type_set;
+   unified = eet_data_descriptor_stream_new(&eddc);
+
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST1", _eet_st1_dd());
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST2", _eet_st2_dd());
+   EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST3", _eet_st3_dd());
+
+   EET_DATA_DESCRIPTOR_ADD_VARIANT(edd, Eet_Variant_Test, "data", data, t, unified);
+
+   unified = eet_data_descriptor_stream_new(&eddc);
+   eet_data_descriptor_element_add(unified, "ST1",
+                                  EET_T_UNKNOW, EET_G_LIST,
+                                  0, 0, NULL, _eet_st1_dd());
+   eet_data_descriptor_element_add(unified, "ST2",
+                                  EET_T_UNKNOW, EET_G_LIST,
+                                  0, 0, NULL, _eet_st2_dd());
+
+   EET_DATA_DESCRIPTOR_ADD_VARIANT(edd, Eet_Variant_Test,
+                                  "data_list", data_list, t, unified);
+
+   EET_DATA_DESCRIPTOR_ADD_LIST(m, Eet_List, "list", list, edd);
+
+   l = calloc(1, sizeof (Eet_List));
+
+#define EVT_NEW(Type_Index)                                    \
+   evt = calloc(1, sizeof (Eet_Variant_Test));                 \
+   evt->t.type = eet_mapping[Type_Index - 1].name;             \
+   st##Type_Index = calloc(1, sizeof (Eet_St##Type_Index));    \
+   _eet_st##Type_Index##_set(st##Type_Index, i);               \
+   evt->data = st##Type_Index;
+
+   for (i = 0; i < 3; ++i)
+     {
+       EVT_NEW(1);
+       l->list = eina_list_append(l->list, evt);
+
+       st1 = calloc(1, sizeof (Eet_St1));
+       _eet_st1_set(st1, i);
+       evt->data_list = eina_list_append(evt->data_list, st1);
+
+       EVT_NEW(2);
+       l->list = eina_list_append(l->list, evt);
+
+       EVT_NEW(3);
+       l->list = eina_list_append(l->list, evt);
+     }
+
+   blob = eet_data_descriptor_encode(m, l, &size);
+   fail_if(!blob || size <= 0);
+
+   l = eet_data_descriptor_decode(m, blob, size);
+   fail_if(!l);
+
+   fail_if(eina_list_count(l->list) != 9);
+
+#define EVT_CMP(Type_Index)                                            \
+   evt = eina_list_nth(l->list, i * 3 + Type_Index - 1);               \
+   fail_if(strcmp(evt->t.type, eet_mapping[Type_Index - 1].name) != 0);        \
+   _eet_st##Type_Index##_cmp(evt->data, i);
+
+   for (i = 0; i < 3; ++i)
+     {
+       EVT_CMP(1);
+
+       fail_if(!evt->data_list);
+       fail_if(eina_list_count(evt->data_list) != 1);
+
+       st1 = eina_list_data_get(evt->data_list);
+       _eet_st1_cmp(st1, i);
+
+       EVT_CMP(2);
+       EVT_CMP(3);
+     }
+
+   eet_shutdown();
+   eina_shutdown();
+}
+END_TEST
+
 Suite *
 eet_suite(void)
 {
@@ -1773,6 +2197,8 @@ eet_suite(void)
    tcase_add_test(tc, eet_test_data_type_encoding_decoding);
    tcase_add_test(tc, eet_test_data_type_dump_undump);
    tcase_add_test(tc, eet_fp);
+   tcase_add_test(tc, eet_test_union);
+   tcase_add_test(tc, eet_test_variant);
    suite_add_tcase(s, tc);
 
    tc = tcase_create("Eet File");