*
* 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);
#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. */
* 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
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;
};
}
/**
+ * 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
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;
/*---*/
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;
Eet_Data_Descriptor_Hash *buckets;
} hash;
} elements;
+
+ Eina_Bool unified_type : 1;
// char *strings;
// int strings_len;
};
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);
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);
{ 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;
#define EET_I_INLINED_STRING 2 << 4
#define EET_I_NULL 3 << 4
+#define EET_MAGIC_VARIANT 0xF1234BC
/*---*/
/* CHAR TYPE */
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;
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;
}
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 ;
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;
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;
}
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)
{
}
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)
{
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");