From dd7595a3475407a7fa96a97393bae8c5220e8762 Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Wed, 4 Jan 2012 18:41:13 +1000 Subject: Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje. Note that embryo wont be used, but I'm not sure yet if you can build edje without it. --- libraries/eet/src/lib/eet_data.c | 4999 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 4999 insertions(+) create mode 100644 libraries/eet/src/lib/eet_data.c (limited to 'libraries/eet/src/lib/eet_data.c') diff --git a/libraries/eet/src/lib/eet_data.c b/libraries/eet/src/lib/eet_data.c new file mode 100644 index 0000000..23b0b97 --- /dev/null +++ b/libraries/eet/src/lib/eet_data.c @@ -0,0 +1,4999 @@ +#ifdef HAVE_CONFIG_H +# include +#endif /* ifdef HAVE_CONFIG_H */ + +#include +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +# include +#endif /* ifdef HAVE_NETINET_IN_H */ + +#ifdef _WIN32 +# include +#endif /* ifdef _WIN32 */ + +#include + +#include "Eet.h" +#include "Eet_private.h" + +#ifdef _WIN32 +# define FMT_CHAR "%c" +# define FMT_UCHAR "%c" +# define FMT_LONG_LONG "%I64i" +# define FMT_ULONG_LONG "%I64u" +#else +# define FMT_CHAR "%hhi" +# define FMT_UCHAR "%hhu" +# define FMT_LONG_LONG "%lli" +# define FMT_ULONG_LONG "%llu" +#endif + +/* + * routines for doing data -> struct and struct -> data conversion + * + * types: + * + * basic types: + * a sequence of... + * + * char + * short + * int + * long long + * float + * double + * unsigned char + * unsigned short + * unsigned int + * unsgined long long + * string + * + * groupings: + * multiple entries ordered as... + * + * fixed size array [ of basic types ] + * variable size array [ of basic types ] + * linked list [ of basic types ] + * hash table [ of basic types ] + * + * need to provide builder/accessor funcs for: + * + * list_next + * list_append + * + * hash_foreach + * hash_add + * + */ + +/*---*/ + +typedef struct _Eet_Data_Element Eet_Data_Element; +typedef struct _Eet_Data_Basic_Type_Codec Eet_Data_Basic_Type_Codec; +typedef struct _Eet_Data_Group_Type_Codec Eet_Data_Group_Type_Codec; +typedef struct _Eet_Data_Chunk Eet_Data_Chunk; +typedef struct _Eet_Data_Stream Eet_Data_Stream; +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; + +/*---*/ + +/* TODO: + * Eet_Data_Basic_Type_Codec (Coder, Decoder) + * Eet_Data_Group_Type_Codec (Coder, Decoder) + */ +struct _Eet_Data_Basic_Type_Codec +{ + int size; + const char *name; + int (*get)(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); + void * (*put)(Eet_Dictionary *ed, const void *src, int *size_ret); +}; + +struct _Eet_Data_Group_Type_Codec +{ + int (*get)(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_in, + char **p, + int *size); + void (*put)(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, + Eet_Data_Stream *ds, + void *data_in); +}; + +struct _Eet_Data_Chunk +{ + char *name; + int len; + int size; + int hash; + void *data; + unsigned char type; + unsigned char group_type; +}; + +struct _Eet_Data_Stream +{ + void *data; + int size; + int pos; +}; + +struct _Eet_Data_Descriptor_Hash +{ + Eet_Data_Element *element; + Eet_Data_Descriptor_Hash *next; +}; + +struct _Eet_Data_Descriptor +{ + const char *name; + const Eet_Dictionary *ed; + int size; + struct + { + void * (*mem_alloc)(size_t size); + void (*mem_free)(void *mem); + char * (*str_alloc)(const char *str); + char * (*str_direct_alloc)(const char *str); + void (*str_free)(const char *str); + void (*str_direct_free)(const char *str); + void * (*list_next)(void *l); + void * (*list_append)(void *l, void *d); + void * (*list_data)(void *l); + void * (*list_free)(void *l); + 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); + void * (*array_alloc)(size_t size); + void (*array_free)(void *mem); + } func; + struct + { + int num; + Eet_Data_Element *set; + struct + { + int size; + Eet_Data_Descriptor_Hash *buckets; + } hash; + } elements; + + Eina_Bool unified_type : 1; +// char *strings; +// int strings_len; +}; + +struct _Eet_Data_Element +{ + const char *name; + const char *counter_name; + const char *directory_name_ptr; + Eet_Data_Descriptor *subtype; + int offset; /* offset in bytes from the base element */ + int count; /* number of elements for a fixed array */ + int counter_offset; /* for a variable array we need the offset of the count variable */ + unsigned char type; /* EET_T_XXX */ + unsigned char group_type; /* EET_G_XXX */ +}; + +struct _Eet_Data_Encode_Hash_Info +{ + Eet_Data_Stream *ds; + Eet_Data_Element *ede; + Eet_Dictionary *ed; +}; + +#define EET_FREE_COUNT 256 +struct _Eet_Free +{ + int ref; + Eina_Array list[EET_FREE_COUNT]; +}; + +struct _Eet_Free_Context +{ + Eet_Free freelist; + Eet_Free freelist_array; + Eet_Free freelist_list; + Eet_Free freelist_hash; + Eet_Free freelist_str; + Eet_Free freelist_direct_str; +}; + +struct _Eet_Variant_Unknow +{ + EINA_MAGIC + + int size; + char data[1]; +}; + +/*---*/ + +static void + eet_free_context_init(Eet_Free_Context *context); +static void + eet_free_context_shutdown(Eet_Free_Context *context); + +static int +eet_data_get_char(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_char(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_short(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_short(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static inline int +eet_data_get_int(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_int(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_long_long(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_long_long(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_float(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_float(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_double(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_double(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_f32p32(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_f32p32(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_f16p16(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_f16p16(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_f8p24(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_f8p24(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static inline int +eet_data_get_string(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_string(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_istring(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_istring(Eet_Dictionary *ed, + const void *src, + int *size_ret); +static int +eet_data_get_null(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_null(Eet_Dictionary *ed, + const void *src, + int *size_ret); + +static int +eet_data_get_type(const Eet_Dictionary *ed, + int type, + const void *src, + const void *src_end, + void *dest); +static void * +eet_data_put_type(Eet_Dictionary *ed, + int type, + const void *src, + int *size_ret); + +static Eet_Node * +eet_data_node_simple_type(int type, + const char *name, + void *dd); + +static int +eet_data_get_unknown(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_in, + char **p, + int *size); +static void +eet_data_put_unknown(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, + Eet_Data_Stream *ds, + void *data_in); +static void +eet_data_put_array(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, + Eet_Data_Stream *ds, + void *data_in); +static int +eet_data_get_array(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 int +eet_data_get_list(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_in, + char **p, + int *size); +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_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); +static void +eet_data_chunk_free(Eet_Data_Chunk *chnk); + +static Eet_Data_Stream * + eet_data_stream_new(void); +static void + eet_data_stream_write(Eet_Data_Stream *ds, + const void *data, + int size); +static void +eet_data_stream_free(Eet_Data_Stream *ds); + +static void +eet_data_chunk_put(Eet_Dictionary *ed, + Eet_Data_Chunk *chnk, + Eet_Data_Stream *ds); + +static int +eet_data_descriptor_encode_hash_cb(void *hash, + const char *key, + void *hdata, + void *fdata); +static void *_eet_data_descriptor_encode(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + const void *data_in, + int *size_ret); +static void *_eet_data_descriptor_decode(Eet_Free_Context *context, + const Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + const void *data_in, + int size_in, + void *data_out, + int size_out); + +/*---*/ + +static const Eet_Data_Basic_Type_Codec eet_basic_codec[] = +{ + {sizeof(char), "char", eet_data_get_char, eet_data_put_char }, + {sizeof(short), "short", eet_data_get_short, eet_data_put_short }, + {sizeof(int), "int", eet_data_get_int, eet_data_put_int }, + {sizeof(long long), "long_long", eet_data_get_long_long, eet_data_put_long_long}, + {sizeof(float), "float", eet_data_get_float, eet_data_put_float }, + {sizeof(double), "double", eet_data_get_double, eet_data_put_double }, + {sizeof(char), "uchar", eet_data_get_char, eet_data_put_char }, + {sizeof(short), "ushort", eet_data_get_short, eet_data_put_short }, + {sizeof(int), "uint", eet_data_get_int, eet_data_put_int }, + {sizeof(long long), "ulong_long", eet_data_get_long_long, eet_data_put_long_long}, + {sizeof(char *), "string", eet_data_get_string, eet_data_put_string }, + {sizeof(char *), "inlined", eet_data_get_istring, eet_data_put_istring }, + {sizeof(void *), "NULL", eet_data_get_null, eet_data_put_null }, + {sizeof(Eina_F32p32), "f32p32", eet_data_get_f32p32, eet_data_put_f32p32 }, + {sizeof(Eina_F16p16), "f16p16", eet_data_get_f16p16, eet_data_put_f16p16 }, + {sizeof(Eina_F8p24), "f8p24", eet_data_get_f8p24, eet_data_put_f8p24 } +}; + +static const Eet_Data_Group_Type_Codec eet_group_codec[] = +{ + { eet_data_get_unknown, eet_data_put_unknown }, + { 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_union, eet_data_put_union }, + { eet_data_get_variant, eet_data_put_variant } +}; + +static int _eet_data_words_bigendian = -1; + +/*---*/ + +#define SWAP64(x) (x) = \ + ((((unsigned long long)(x) & 0x00000000000000ffULL) << 56) | \ + (((unsigned long long)(x) & 0x000000000000ff00ULL) << 40) | \ + (((unsigned long long)(x) & 0x0000000000ff0000ULL) << 24) | \ + (((unsigned long long)(x) & 0x00000000ff000000ULL) << 8) | \ + (((unsigned long long)(x) & 0x000000ff00000000ULL) >> 8) | \ + (((unsigned long long)(x) & 0x0000ff0000000000ULL) >> 24) | \ + (((unsigned long long)(x) & 0x00ff000000000000ULL) >> 40) | \ + (((unsigned long long)(x) & 0xff00000000000000ULL) >> 56)) +#define SWAP32(x) (x) = \ + ((((int)(x) & 0x000000ff) << 24) | \ + (((int)(x) & 0x0000ff00) << 8) | \ + (((int)(x) & 0x00ff0000) >> 8) | \ + (((int)(x) & 0xff000000) >> 24)) +#define SWAP16(x) (x) = \ + ((((short)(x) & 0x00ff) << 8) | \ + (((short)(x) & 0xff00) >> 8)) + +#ifdef CONV8 +# undef CONV8 +#endif /* ifdef CONV8 */ +#ifdef CONV16 +# undef CONV16 +#endif /* ifdef CONV16 */ +#ifdef CONV32 +# undef CONV32 +#endif /* ifdef CONV32 */ +#ifdef CONV64 +# undef CONV64 +#endif /* ifdef CONV64 */ + +#define CONV8(x) +#define CONV16(x) {if (_eet_data_words_bigendian) {SWAP16(x); }} +#define CONV32(x) {if (_eet_data_words_bigendian) {SWAP32(x); }} +#define CONV64(x) {if (_eet_data_words_bigendian) {SWAP64(x); }} + +#define IS_SIMPLE_TYPE(Type) (Type > EET_T_UNKNOW && Type < EET_T_LAST) +#define IS_POINTER_TYPE(Type) (Type >= EET_T_STRING && Type <= EET_T_NULL) + +#define POINTER_TYPE_DECODE(Context, \ + Ed, \ + Edd, \ + Ede, \ + Echnk, \ + Type, \ + Data, \ + P, \ + Size, \ + Label) \ + do { \ + int ___r; \ + ___r = eet_data_get_unknown(Context, \ + Ed, \ + Edd, Ede, \ + Echnk, \ + Type, EET_G_UNKNOWN, \ + Data, P, Size); \ + if (!___r) { goto Label; } \ + } while (0) + +#define STRUCT_TYPE_DECODE(Data_Ret, Context, Ed, Ede, Data, Size, SubSize, Label) \ + do { \ + Data_Ret = _eet_data_descriptor_decode(Context, \ + Ed, \ + Ede, \ + Data, \ + Size, \ + SubSize > 0 ? Data_Ret : NULL, \ + SubSize); \ + if (!Data_Ret) { goto Label; } \ + } while (0) + +#define EET_I_STRING 1 << 4 +#define EET_I_INLINED_STRING 2 << 4 +#define EET_I_NULL 3 << 4 + +#define EET_MAGIC_VARIANT 0xF1234BC +/*---*/ + +/* CHAR TYPE */ +static int +eet_data_get_char(const Eet_Dictionary *ed __UNUSED__, + const void *src, + const void *src_end, + void *dst) +{ + char *s, *d; + + if (((char *)src + sizeof(char)) > (char *)src_end) + return -1; + + s = (char *)src; + d = (char *)dst; + *d = *s; + CONV8(*d); + return sizeof(char); +} /* eet_data_get_char */ + +static void * +eet_data_put_char(Eet_Dictionary *ed __UNUSED__, + const void *src, + int *size_ret) +{ + char *s, *d; + + d = (char *)malloc(sizeof(char)); + if (!d) + return NULL; + + s = (char *)src; + *d = *s; + CONV8(*d); + *size_ret = sizeof(char); + return d; +} /* eet_data_put_char */ + +/* SHORT TYPE */ +static int +eet_data_get_short(const Eet_Dictionary *ed __UNUSED__, + const void *src, + const void *src_end, + void *dst) +{ + short *d; + + if (((char *)src + sizeof(short)) > (char *)src_end) + return -1; + + memcpy(dst, src, sizeof(short)); + d = (short *)dst; + CONV16(*d); + return sizeof(short); +} /* eet_data_get_short */ + +static void * +eet_data_put_short(Eet_Dictionary *ed __UNUSED__, + const void *src, + int *size_ret) +{ + short *s, *d; + + d = (short *)malloc(sizeof(short)); + if (!d) + return NULL; + + s = (short *)src; + *d = *s; + CONV16(*d); + *size_ret = sizeof(short); + return d; +} /* eet_data_put_short */ + +/* INT TYPE */ +static inline int +eet_data_get_int(const Eet_Dictionary *ed __UNUSED__, + const void *src, + const void *src_end, + void *dst) +{ + int *d; + + if (((char *)src + sizeof(int)) > (char *)src_end) + return -1; + + memcpy(dst, src, sizeof(int)); + d = (int *)dst; + CONV32(*d); + return sizeof(int); +} /* eet_data_get_int */ + +static void * +eet_data_put_int(Eet_Dictionary *ed __UNUSED__, + const void *src, + int *size_ret) +{ + int *s, *d; + + d = (int *)malloc(sizeof(int)); + if (!d) + return NULL; + + s = (int *)src; + *d = *s; + CONV32(*d); + *size_ret = sizeof(int); + return d; +} /* eet_data_put_int */ + +/* LONG LONG TYPE */ +static int +eet_data_get_long_long(const Eet_Dictionary *ed __UNUSED__, + const void *src, + const void *src_end, + void *dst) +{ + unsigned long long *d; + + if (((char *)src + sizeof(unsigned long long)) > (char *)src_end) + return -1; + + memcpy(dst, src, sizeof(unsigned long long)); + d = (unsigned long long *)dst; + CONV64(*d); + return sizeof(unsigned long long); +} /* eet_data_get_long_long */ + +static void * +eet_data_put_long_long(Eet_Dictionary *ed __UNUSED__, + const void *src, + int *size_ret) +{ + unsigned long long *s, *d; + + d = (unsigned long long *)malloc(sizeof(unsigned long long)); + if (!d) + return NULL; + + s = (unsigned long long *)src; + *d = *s; + CONV64(*d); + *size_ret = sizeof(unsigned long long); + return d; +} /* eet_data_put_long_long */ + +/* STRING TYPE */ +static inline int +eet_data_get_string_hash(const Eet_Dictionary *ed, + const void *src, + const void *src_end) +{ + if (ed) + { + int idx; + + if (eet_data_get_int(ed, src, src_end, &idx) < 0) + return -1; + + return eet_dictionary_string_get_hash(ed, idx); + } + + return -1; +} /* eet_data_get_string_hash */ + +static inline int +eet_data_get_string(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dst) +{ + char *s, **d; + + d = (char **)dst; + + if (ed) + { + const char *str; + int idx; + + if (eet_data_get_int(ed, src, src_end, &idx) < 0) + return -1; + + str = eet_dictionary_string_get_char(ed, idx); + if (!str) + return -1; + + *d = (char *)str; + return eet_dictionary_string_get_size(ed, idx); + } + + s = (char *)src; + if (!s) + { + *d = NULL; + return 0; + } + + *d = s; + return strlen(s) + 1; +} /* eet_data_get_string */ + +static void * +eet_data_put_string(Eet_Dictionary *ed, + const void *src, + int *size_ret) +{ + char *s, *d; + int len; + + if (ed) + { + const char *str; + int idx; + + str = *((const char **)src); + if (!str) + return NULL; + + idx = eet_dictionary_string_add(ed, str); + if (idx == -1) + return NULL; + + return eet_data_put_int(ed, &idx, size_ret); + } + + s = (char *)(*((char **)src)); + if (!s) + return NULL; + + len = strlen(s); + d = malloc(len + 1); + if (!d) + return NULL; + + memcpy(d, s, len + 1); + *size_ret = len + 1; + return d; +} /* eet_data_put_string */ + +/* ALWAYS INLINED STRING TYPE */ +static int +eet_data_get_istring(const Eet_Dictionary *ed __UNUSED__, + const void *src, + const void *src_end, + void *dst) +{ + return eet_data_get_string(NULL, src, src_end, dst); +} /* eet_data_get_istring */ + +static void * +eet_data_put_istring(Eet_Dictionary *ed __UNUSED__, + const void *src, + int *size_ret) +{ + return eet_data_put_string(NULL, src, size_ret); +} /* eet_data_put_istring */ + +/* ALWAYS NULL TYPE */ +static int +eet_data_get_null(const Eet_Dictionary *ed __UNUSED__, + const void *src __UNUSED__, + const void *src_end __UNUSED__, + void *dst) +{ + char **d; + + d = (char **)dst; + + *d = NULL; + return 1; +} /* eet_data_get_null */ + +static void * +eet_data_put_null(Eet_Dictionary *ed __UNUSED__, + const void *src __UNUSED__, + int *size_ret) +{ + *size_ret = 0; + return NULL; +} /* eet_data_put_null */ + +/** + * Fast lookups of simple doubles/floats. + * + * These aren't properly a cache because they don't store pre-calculated + * values, but have a so simple math that is almost as fast. + */ +static inline int +_eet_data_float_cache_get(const char *s, + int len, + float *d) +{ + /* fast handle of simple case 0xMp+E*/ + if ((len == 6) && (s[0] == '0') && (s[1] == 'x') && (s[3] == 'p')) + { + int mantisse = (s[2] >= 'a') ? (s[2] - 'a' + 10) : (s[2] - '0'); + int exponent = (s[5] - '0'); + + if (s[4] == '+') + *d = (float)(mantisse << exponent); + else + *d = (float)mantisse / (float)(1 << exponent); + + return 1; + } + + return 0; +} /* _eet_data_float_cache_get */ + +static inline int +_eet_data_double_cache_get(const char *s, + int len, + double *d) +{ + /* fast handle of simple case 0xMp+E*/ + if ((len == 6) && (s[0] == '0') && (s[1] == 'x') && (s[3] == 'p')) + { + int mantisse = (s[2] >= 'a') ? (s[2] - 'a' + 10) : (s[2] - '0'); + int exponent = (s[5] - '0'); + + if (s[4] == '+') + *d = (double)(mantisse << exponent); + else + *d = (double)mantisse / (double)(1 << exponent); + + return 1; + } + + return 0; +} /* _eet_data_double_cache_get */ + +/* FLOAT TYPE */ +static int +eet_data_get_float(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dst) +{ + float *d; + int idx; + + d = (float *)dst; + if (!ed) + { + const char *s, *p; + long long mantisse; + long exponent; + int len; + + s = (const char *)src; + p = s; + len = 0; + while ((p < (const char *)src_end) && (*p != 0)) {len++; p++; } + + if (_eet_data_float_cache_get(s, len, d) != 0) + return len + 1; + + if (eina_convert_atod(s, len, &mantisse, &exponent) == EINA_FALSE) + return -1; + + *d = (float)ldexp((double)mantisse, exponent); + + return len + 1; + } + + if (eet_data_get_int(ed, src, src_end, &idx) < 0) + return -1; + + if (!eet_dictionary_string_get_float(ed, idx, d)) + return -1; + + return 1; +} /* eet_data_get_float */ + +static void * +eet_data_put_float(Eet_Dictionary *ed, + const void *src, + int *size_ret) +{ + char buf[128]; + int idx; + + eina_convert_dtoa((double)(*(float *)src), buf); + + if (!ed) + { + char *d; + int len; + + len = strlen(buf); + d = malloc(len + 1); + if (!d) + return NULL; + + memcpy(d, buf, len + 1); + *size_ret = len + 1; + return d; + } + + idx = eet_dictionary_string_add(ed, buf); + if (idx == -1) + return NULL; + + return eet_data_put_int(ed, &idx, size_ret); +} /* eet_data_put_float */ + +/* DOUBLE TYPE */ +static int +eet_data_get_double(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dst) +{ + double *d; + int idx; + + d = (double *)dst; + + if (!ed) + { + const char *s, *p; + long long mantisse = 0; + long exponent = 0; + int len; + + s = (const char *)src; + p = s; + len = 0; + while ((p < (const char *)src_end) && (*p != 0)) {len++; p++; } + + if (_eet_data_double_cache_get(s, len, d) != 0) + return len + 1; + + if (eina_convert_atod(s, len, &mantisse, &exponent) == EINA_FALSE) + return -1; + + *d = ldexp((double)mantisse, exponent); + + return len + 1; + } + + if (eet_data_get_int(ed, src, src_end, &idx) < 0) + return -1; + + if (!eet_dictionary_string_get_double(ed, idx, d)) + return -1; + + return 1; +} /* eet_data_get_double */ + +static void * +eet_data_put_double(Eet_Dictionary *ed, + const void *src, + int *size_ret) +{ + char buf[128]; + int idx; + + eina_convert_dtoa((double)(*(double *)src), buf); + + if (!ed) + { + char *d; + int len; + + len = strlen(buf); + d = malloc(len + 1); + if (!d) + return NULL; + + memcpy(d, buf, len + 1); + *size_ret = len + 1; + + return d; + } + + idx = eet_dictionary_string_add(ed, buf); + if (idx == -1) + return NULL; + + return eet_data_put_int(ed, &idx, size_ret); +} /* eet_data_put_double */ + +static int +eet_data_get_f32p32(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dst) +{ + Eina_F32p32 *fp; + int idx; + + fp = (Eina_F32p32 *)dst; + + if (!ed) + { + const char *s, *p; + int len; + + s = (const char *)src; + p = s; + len = 0; + while ((p < (const char *)src_end) && (*p != 0)) { len++; p++; } + + if (!(eina_convert_atofp(s, len, fp))) + return -1; + + return 1; + } + + if (eet_data_get_int(ed, src, src_end, &idx) < 0) + return -1; + + if (!eet_dictionary_string_get_fp(ed, idx, fp)) + return -1; + + return 1; +} /* eet_data_get_f32p32 */ + +static void * +eet_data_put_f32p32(Eet_Dictionary *ed, + const void *src, + int *size_ret) +{ + char buf[128]; + int idx; + + eina_convert_fptoa((Eina_F32p32)(*(Eina_F32p32 *)src), buf); + + if (!ed) + { + char *d; + int len; + + len = strlen(buf); + d = malloc(len + 1); + if (!d) + return NULL; + + memcpy(d, buf, len + 1); + *size_ret = len + 1; + + return d; + } + + idx = eet_dictionary_string_add(ed, buf); + if (idx == -1) + return NULL; + + return eet_data_put_int(ed, &idx, size_ret); +} /* eet_data_put_f32p32 */ + +static int +eet_data_get_f16p16(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dst) +{ + Eina_F32p32 tmp; + Eina_F16p16 *fp; + + fp = (Eina_F16p16 *)dst; + + if (eet_data_get_f32p32(ed, src, src_end, &tmp) < 0) + return -1; + + *fp = eina_f32p32_to_f16p16(tmp); + return 1; +} /* eet_data_get_f16p16 */ + +static void * +eet_data_put_f16p16(Eet_Dictionary *ed, + const void *src, + int *size_ret) +{ + Eina_F32p32 tmp; + + tmp = eina_f16p16_to_f32p32((Eina_F16p16)(*(Eina_F16p16 *)src)); + return eet_data_put_f32p32(ed, &tmp, size_ret); +} /* eet_data_put_f16p16 */ + +static int +eet_data_get_f8p24(const Eet_Dictionary *ed, + const void *src, + const void *src_end, + void *dst) +{ + Eina_F32p32 tmp; + Eina_F8p24 *fp; + + fp = (Eina_F8p24 *)dst; + + if (eet_data_get_f32p32(ed, src, src_end, &tmp) < 0) + return -1; + + *fp = eina_f32p32_to_f8p24(tmp); + return 1; +} /* eet_data_get_f8p24 */ + +static void * +eet_data_put_f8p24(Eet_Dictionary *ed, + const void *src, + int *size_ret) +{ + Eina_F32p32 tmp; + + tmp = eina_f8p24_to_f32p32((Eina_F8p24)(*(Eina_F8p24 *)src)); + return eet_data_put_f32p32(ed, &tmp, size_ret); +} /* eet_data_put_f8p24 */ + +static inline int +eet_data_get_type(const Eet_Dictionary *ed, + int type, + const void *src, + const void *src_end, + void *dest) +{ + int ret; + + ret = eet_basic_codec[type - 1].get(ed, src, src_end, dest); + return ret; +} /* eet_data_get_type */ + +static inline void * +eet_data_put_type(Eet_Dictionary *ed, + int type, + const void *src, + int *size_ret) +{ + void *ret; + + ret = eet_basic_codec[type - 1].put(ed, src, size_ret); + return ret; +} /* eet_data_put_type */ + +static inline Eina_Bool +eet_data_type_match(int type1, + int type2) +{ + if (type1 == type2) + return EINA_TRUE; + + /* Note: All floating point type are equivalent and could be read + without problem by any other floating point getter. */ + switch (type1) + { + case EET_T_FLOAT: + case EET_T_DOUBLE: + case EET_T_F32P32: + case EET_T_F16P16: + case EET_T_F8P24: + switch (type2) + { + case EET_T_FLOAT: + case EET_T_DOUBLE: + case EET_T_F32P32: + case EET_T_F16P16: + case EET_T_F8P24: + return EINA_TRUE; + + default: + break; + } /* switch */ + break; + + default: + break; + } /* switch */ + + return EINA_FALSE; +} /* eet_data_type_match */ + +/* chunk format... + * + * char[4] = "CHnK"; // untyped data ... or + * char[4] = "CHKx"; // typed data - x == type + * + * int = chunk size (including magic string); + * char[] = chunk magic/name string (0 byte terminated); + * ... sub-chunks (a chunk can contain chuncks recusrively) ... + * or + * ... payload data ... + * + */ + +static inline void +eet_data_chunk_get(const Eet_Dictionary *ed, + Eet_Data_Chunk *chnk, + const void *src, + int size) +{ + const char *s; + int ret1, ret2; + + if (!src) + return; + + if (size <= 8) + return; + + if (!chnk) + return; + + s = src; + if (s[2] == 'K') + { + if ((s[0] != 'C') || (s[1] != 'H') || (s[2] != 'K')) + return; + + chnk->type = (unsigned char)(s[3]); + if (chnk->type >= EET_I_LIMIT) + { + chnk->group_type = + ((chnk->type - EET_I_LIMIT) & 0xF) + EET_G_UNKNOWN; + switch ((chnk->type - EET_I_LIMIT) & 0xF0) + { +#define EET_UNMATCH_TYPE(Type) \ +case EET_I_ ## Type: chnk->type = EET_T_ ## Type; break; + + EET_UNMATCH_TYPE(STRING); + EET_UNMATCH_TYPE(INLINED_STRING); + EET_UNMATCH_TYPE(NULL); + + default: + return; + } /* switch */ + } + else if (chnk->type > EET_T_LAST) + { + chnk->group_type = chnk->type; + chnk->type = EET_T_UNKNOW; + } + else + chnk->group_type = EET_G_UNKNOWN; + if ((chnk->type >= EET_T_LAST) || + (chnk->group_type >= + EET_G_LAST)) + { + chnk->type = 0; + chnk->group_type = 0; + } + } + else if ((s[0] != 'C') || (s[1] != 'H') || (s[2] != 'n') || (s[3] != 'K')) + return; + + ret1 = eet_data_get_type(ed, EET_T_INT, (s + 4), (s + size), &(chnk->size)); + + if (ret1 <= 0) + return; + + if ((chnk->size < 0) || ((chnk->size + 8) > size)) + return; + + ret2 = eet_data_get_type(ed, EET_T_STRING, (s + 8), (s + size), &(chnk->name)); + + if (ret2 <= 0) + return; + + chnk->len = ret2; + + /* Precalc hash */ + chnk->hash = eet_data_get_string_hash(ed, (s + 8), (s + size)); + + if (ed) + { + chnk->data = (char *)src + 4 + ret1 + sizeof(int); + chnk->size -= sizeof(int); + } + else + { + chnk->data = (char *)src + 4 + ret1 + chnk->len; + chnk->size -= chnk->len; + } + + return; +} /* eet_data_chunk_get */ + +static inline Eet_Data_Chunk * +eet_data_chunk_new(void *data, + int size, + const char *name, + int type, + int group_type) +{ + Eet_Data_Chunk *chnk; + + if (!name) + return NULL; + + chnk = calloc(1, sizeof(Eet_Data_Chunk)); + if (!chnk) + return NULL; + + /* Note: Another security, so older eet library could read file + saved with fixed point value. */ + if (type == EET_T_F32P32 + || type == EET_T_F16P16 + || type == EET_T_F8P24) + type = EET_T_DOUBLE; + + chnk->name = strdup(name); + chnk->len = strlen(name) + 1; + chnk->size = size; + chnk->data = data; + chnk->type = type; + chnk->group_type = group_type; + return chnk; +} /* eet_data_chunk_new */ + +static inline void +eet_data_chunk_free(Eet_Data_Chunk *chnk) +{ + if (chnk->name) + free(chnk->name); + + free(chnk); +} /* eet_data_chunk_free */ + +static inline Eet_Data_Stream * +eet_data_stream_new(void) +{ + Eet_Data_Stream *ds; + + ds = calloc(1, sizeof(Eet_Data_Stream)); + if (!ds) + return NULL; + + return ds; +} /* eet_data_stream_new */ + +static inline void +eet_data_stream_free(Eet_Data_Stream *ds) +{ + if (ds->data) + free(ds->data); + + free(ds); +} /* eet_data_stream_free */ + +static inline void +eet_data_stream_flush(Eet_Data_Stream *ds) +{ + free(ds); +} /* eet_data_stream_flush */ + +static inline void +eet_data_stream_write(Eet_Data_Stream *ds, + const void *data, + int size) +{ + char *p; + + if ((ds->pos + size) > ds->size) + { + ds->data = realloc(ds->data, ds->size + size + 512); + if (!ds->data) + { + ds->pos = 0; + ds->size = 0; + return; + } + + ds->size = ds->size + size + 512; + } + + p = ds->data; + memcpy(p + ds->pos, data, size); + ds->pos += size; +} /* eet_data_stream_write */ + +static void +eet_data_chunk_put(Eet_Dictionary *ed, + Eet_Data_Chunk *chnk, + Eet_Data_Stream *ds) +{ + int *size; + void *string; + int s; + int size_ret = 0; + int string_ret = 0; + unsigned char buf[4] = "CHK"; + + /* disable this check - it will allow empty chunks to be written. this is + * right for corner-cases when y have a struct with empty fields (empty + * strings or empty list ptrs etc.) */ + /* if (!chnk->data && chnk->type != EET_T_NULL) return; */ + /* chunk head */ + +/* eet_data_stream_write(ds, "CHnK", 4);*/ + if (chnk->type != EET_T_UNKNOW) + { + if (chnk->group_type != EET_G_UNKNOWN) + { + int type = EET_I_LIMIT + chnk->group_type - EET_G_UNKNOWN; + + switch (chnk->type) + { + /* Only make sense with pointer type. */ +#define EET_MATCH_TYPE(Type) \ +case EET_T_ ## Type: type += EET_I_ ## Type; break; + + EET_MATCH_TYPE(STRING); + EET_MATCH_TYPE(INLINED_STRING); + EET_MATCH_TYPE(NULL); + + default: + return; + } /* switch */ + + buf[3] = type; + } + else + buf[3] = chnk->type; + } + else + buf[3] = chnk->group_type; + + string = eet_data_put_string(ed, &chnk->name, &string_ret); + if (!string) + return; + + /* size of chunk payload data + name */ + s = chnk->size + string_ret; + size = eet_data_put_int(ed, &s, &size_ret); + + /* FIXME: If something goes wrong the resulting file will be corrupted. */ + if (!size) + goto on_error; + + eet_data_stream_write(ds, buf, 4); + + /* write chunk length */ + eet_data_stream_write(ds, size, size_ret); + + /* write chunk name */ + eet_data_stream_write(ds, string, string_ret); + + /* write payload */ + if (chnk->data) + eet_data_stream_write(ds, chnk->data, chnk->size); + + free(string); +on_error: + free(size); +} /* eet_data_chunk_put */ + +/*---*/ + +static void +_eet_descriptor_hash_new(Eet_Data_Descriptor *edd) +{ + int i; + + edd->elements.hash.size = 1 << 6; + edd->elements.hash.buckets = calloc( + 1, + sizeof(Eet_Data_Descriptor_Hash) * + edd->elements.hash.size); + for (i = 0; i < edd->elements.num; i++) + { + Eet_Data_Element *ede; + int hash; + + ede = &(edd->elements.set[i]); + hash = _eet_hash_gen((char *)ede->name, 6); + if (!edd->elements.hash.buckets[hash].element) + edd->elements.hash.buckets[hash].element = ede; + else + { + Eet_Data_Descriptor_Hash *bucket; + + bucket = calloc(1, sizeof(Eet_Data_Descriptor_Hash)); + bucket->element = ede; + bucket->next = edd->elements.hash.buckets[hash].next; + edd->elements.hash.buckets[hash].next = bucket; + } + } +} /* _eet_descriptor_hash_new */ + +static void +_eet_descriptor_hash_free(Eet_Data_Descriptor *edd) +{ + int i; + + for (i = 0; i < edd->elements.hash.size; i++) + { + Eet_Data_Descriptor_Hash *bucket, *pbucket; + + bucket = edd->elements.hash.buckets[i].next; + while (bucket) + { + pbucket = bucket; + bucket = bucket->next; + free(pbucket); + } + } + if (edd->elements.hash.buckets) + free(edd->elements.hash.buckets); +} /* _eet_descriptor_hash_free */ + +static Eet_Data_Element * +_eet_descriptor_hash_find(Eet_Data_Descriptor *edd, + char *name, + int hash) +{ + Eet_Data_Descriptor_Hash *bucket; + + if (hash < 0) + hash = _eet_hash_gen(name, 6); + else + hash &= 0x3f; + + if (!edd->elements.hash.buckets[hash].element) + return NULL; /* + When we use the dictionary as a source for chunk name, we will always + have the same pointer in name. It's a good idea to just compare pointer + instead of running strcmp on both string. + */ + + if (edd->elements.hash.buckets[hash].element->directory_name_ptr == name) + return edd->elements.hash.buckets[hash].element; + + if (!strcmp(edd->elements.hash.buckets[hash].element->name, name)) + { + edd->elements.hash.buckets[hash].element->directory_name_ptr = name; + return edd->elements.hash.buckets[hash].element; + } + + bucket = edd->elements.hash.buckets[hash].next; + while (bucket) + { + if (bucket->element->directory_name_ptr == name) + return bucket->element; + + if (!strcmp(bucket->element->name, name)) + { + bucket->element->directory_name_ptr = name; + return bucket->element; + } + + bucket = bucket->next; + } + return NULL; +} /* _eet_descriptor_hash_find */ + +static void * +_eet_mem_alloc(size_t size) +{ + return calloc(1, size); +} /* _eet_mem_alloc */ + +static void +_eet_mem_free(void *mem) +{ + free(mem); +} /* _eet_mem_free */ + +static char * +_eet_str_alloc(const char *str) +{ + return strdup(str); +} /* _eet_str_alloc */ + +static void +_eet_str_free(const char *str) +{ + free((char *)str); +} /* _eet_str_free */ + +static Eina_Hash * +_eet_eina_hash_add_alloc(Eina_Hash *hash, + const char *key, + void *data) +{ + if (!hash) + hash = eina_hash_string_small_new(NULL); + + if (!hash) + return NULL; + + eina_hash_add(hash, key, data); + return hash; +} /* _eet_eina_hash_add_alloc */ + +static Eina_Hash * +_eet_eina_hash_direct_add_alloc(Eina_Hash *hash, + const char *key, + void *data) +{ + if (!hash) + hash = eina_hash_string_small_new(NULL); + + if (!hash) + return NULL; + + eina_hash_direct_add(hash, key, data); + return hash; +} /* _eet_eina_hash_direct_add_alloc */ + +static char * +_eet_str_direct_alloc(const char *str) +{ + return (char *)str; +} /* _eet_str_direct_alloc */ + +static void +_eet_str_direct_free(const char *str __UNUSED__) +{ +} /* _eet_str_direct_free */ + +static void +_eet_eina_hash_foreach(void *hash, + Eina_Hash_Foreach cb, + void *fdata) +{ + if (hash) + eina_hash_foreach(hash, cb, fdata); +} /* _eet_eina_hash_foreach */ + +static void +_eet_eina_hash_free(void *hash) +{ + if (hash) + eina_hash_free(hash); +} /* _eet_eina_hash_free */ + +/*---*/ +EAPI Eina_Bool +eet_eina_stream_data_descriptor_class_set(Eet_Data_Descriptor_Class *eddc, + /* When we change the structure content in the future, we need to handle old structure type too */ + unsigned int eddc_size, + const char *name, + int size) +{ + if (!eddc || !name || eddc_size != sizeof (Eet_Data_Descriptor_Class)) + return EINA_FALSE; + + eddc->name = name; + eddc->size = size; + eddc->version = EET_DATA_DESCRIPTOR_CLASS_VERSION; + + eddc->func.mem_alloc = _eet_mem_alloc; + eddc->func.mem_free = _eet_mem_free; + eddc->func.str_alloc = (char *(*)(const char *))eina_stringshare_add; + eddc->func.str_free = eina_stringshare_del; + eddc->func.list_next = (void *(*)(void *))eina_list_next; + eddc->func.list_append = (void *(*)(void *, void *))eina_list_append; + eddc->func.list_data = (void *(*)(void *))eina_list_data_get; + eddc->func.list_free = (void *(*)(void *))eina_list_free; + eddc->func.hash_foreach = (void (*)(void *, int (*)(void *, const char *, void *, void *), void *))_eet_eina_hash_foreach; + eddc->func.hash_add = (void *(*)(void *, const char *, void *))_eet_eina_hash_add_alloc; + eddc->func.hash_free = (void (*)(void *))_eet_eina_hash_free; + + /* This will cause an ABI incompatibility */ + eddc->func.array_alloc = _eet_mem_alloc; + eddc->func.array_free = _eet_mem_free; + + return EINA_TRUE; +} /* eet_eina_stream_data_descriptor_class_set */ + +EAPI Eina_Bool +eet_eina_file_data_descriptor_class_set(Eet_Data_Descriptor_Class *eddc, + /* When we change the structure content in the future, we need to handle old structure type too */ + unsigned int eddc_size, + const char *name, + int size) +{ + if (!eet_eina_stream_data_descriptor_class_set(eddc, eddc_size, name, size)) + return EINA_FALSE; + + eddc->version = EET_DATA_DESCRIPTOR_CLASS_VERSION; + + eddc->func.hash_add = (void *(*)(void *, const char *, void *))_eet_eina_hash_direct_add_alloc; + eddc->func.str_direct_alloc = _eet_str_direct_alloc; + eddc->func.str_direct_free = _eet_str_direct_free; + + return EINA_TRUE; +} /* eet_eina_file_data_descriptor_class_set */ + +static Eet_Data_Descriptor * +_eet_data_descriptor_new(const Eet_Data_Descriptor_Class *eddc, + int version) +{ + Eet_Data_Descriptor *edd; + + if (!eddc) + return NULL; + + edd = calloc(1, sizeof (Eet_Data_Descriptor)); + if (!edd) + return NULL; + + edd->name = eddc->name; + edd->ed = NULL; + edd->size = eddc->size; + edd->func.mem_alloc = _eet_mem_alloc; + edd->func.mem_free = _eet_mem_free; + edd->func.str_alloc = _eet_str_alloc; + edd->func.str_free = _eet_str_free; + if (eddc->func.mem_alloc) + edd->func.mem_alloc = eddc->func.mem_alloc; + + if (eddc->func.mem_free) + edd->func.mem_free = eddc->func.mem_free; + + if (eddc->func.str_alloc) + edd->func.str_alloc = eddc->func.str_alloc; + + if (eddc->func.str_free) + edd->func.str_free = eddc->func.str_free; + + edd->func.list_next = eddc->func.list_next; + edd->func.list_append = eddc->func.list_append; + edd->func.list_data = eddc->func.list_data; + edd->func.list_free = eddc->func.list_free; + edd->func.hash_foreach = eddc->func.hash_foreach; + edd->func.hash_add = eddc->func.hash_add; + edd->func.hash_free = eddc->func.hash_free; + + 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; + } + + if (eddc->version > 3) + { + edd->func.array_alloc = eddc->func.array_alloc; + edd->func.array_free = eddc->func.array_free; + } + + return edd; +} /* _eet_data_descriptor_new */ + +EAPI Eet_Data_Descriptor * +eet_data_descriptor_new(const char *name, + int size, + Eet_Descriptor_List_Next_Callback func_list_next, + Eet_Descriptor_List_Append_Callback func_list_append, + Eet_Descriptor_List_Data_Callback func_list_data, + Eet_Descriptor_List_Free_Callback func_list_free, + Eet_Descriptor_Hash_Foreach_Callback func_hash_foreach, + Eet_Descriptor_Hash_Add_Callback func_hash_add, + Eet_Descriptor_Hash_Free_Callback func_hash_free) +{ + Eet_Data_Descriptor_Class eddc; + + if (!name) + return NULL; + + memset(&eddc, 0, sizeof (Eet_Data_Descriptor_Class)); + + eddc.name = name; + eddc.size = size; + eddc.version = 0; + + eddc.func.list_next = func_list_next; + eddc.func.list_append = func_list_append; + eddc.func.list_data = func_list_data; + eddc.func.list_free = func_list_free; + eddc.func.hash_foreach = func_hash_foreach; + eddc.func.hash_add = func_hash_add; + eddc.func.hash_free = func_hash_free; + + return _eet_data_descriptor_new(&eddc, 0); +} /* eet_data_descriptor_new */ + +EAPI Eet_Data_Descriptor * +eet_data_descriptor2_new(const Eet_Data_Descriptor_Class *eddc) +{ + return _eet_data_descriptor_new(eddc, 1); +} /* eet_data_descriptor2_new */ + +EAPI Eet_Data_Descriptor * +eet_data_descriptor3_new(const Eet_Data_Descriptor_Class *eddc) +{ + return _eet_data_descriptor_new(eddc, 2); +} /* eet_data_descriptor3_new */ + +EAPI Eet_Data_Descriptor * +eet_data_descriptor_stream_new(const Eet_Data_Descriptor_Class *eddc) +{ + return _eet_data_descriptor_new(eddc, 1); +} /* eet_data_descriptor_stream_new */ + +EAPI Eet_Data_Descriptor * +eet_data_descriptor_file_new(const Eet_Data_Descriptor_Class *eddc) +{ + return _eet_data_descriptor_new(eddc, 2); +} /* eet_data_descriptor_file_new */ + +EAPI void +eet_data_descriptor_free(Eet_Data_Descriptor *edd) +{ + if (!edd) + return; + + _eet_descriptor_hash_free(edd); + if (edd->elements.set) + free(edd->elements.set); + + free(edd); +} /* eet_data_descriptor_free */ + +EAPI void +eet_data_descriptor_element_add(Eet_Data_Descriptor *edd, + const char *name, + int type, + int group_type, + int offset, + int count, +/* int counter_offset, */ + const char *counter_name /* FIXME: Useless should go on a major release */, + Eet_Data_Descriptor *subtype) +{ + Eet_Data_Element *ede; + Eet_Data_Element *tmp; + + /* UNION, VARIANT type would not work with simple type, we need a way to map the type. */ + if ((group_type == EET_G_UNION + || group_type == EET_G_VARIANT) + && + (type != EET_T_UNKNOW + || !subtype + || !subtype->func.type_get + || !subtype->func.type_set)) + return; + + /* VARIANT type will only work if the map only contains EET_G_*, but not 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; + + edd->elements.set = tmp; + ede = &(edd->elements.set[edd->elements.num - 1]); + ede->name = name; + ede->directory_name_ptr = NULL; + + /* + * We do a special case when we do list,hash or whatever group of simple type. + * Instead of handling it in encode/decode/dump/undump, we create an + * implicit structure with only the simple type. + */ + if ((group_type > EET_G_UNKNOWN) + && (group_type < EET_G_LAST) + && (((type > EET_T_UNKNOW) && (type < EET_T_STRING)) + || ((type > EET_T_NULL) && (type < EET_T_LAST))) + && (!subtype)) + { + subtype = calloc(1, sizeof (Eet_Data_Descriptor)); + if (!subtype) + return; + + subtype->name = "implicit"; + subtype->size = eet_basic_codec[type - 1].size; + memcpy(&subtype->func, &edd->func, sizeof(subtype->func)); + + eet_data_descriptor_element_add(subtype, + eet_basic_codec[type - 1].name, + type, + EET_G_UNKNOWN, + 0, + 0, + /* 0, */ NULL, + NULL); + type = EET_T_UNKNOW; + } + + ede->type = type; + ede->group_type = group_type; + ede->offset = offset; + ede->count = count; + /* FIXME: For the time being, VAR_ARRAY, UNION and VARIANT will put the counter_offset in count. */ + ede->counter_offset = count; +/* ede->counter_offset = counter_offset; */ + ede->counter_name = counter_name; + + ede->subtype = subtype; +} /* eet_data_descriptor_element_add */ + +EAPI void * +eet_data_read_cipher(Eet_File *ef, + Eet_Data_Descriptor *edd, + const char *name, + const char *cipher_key) +{ + const Eet_Dictionary *ed = NULL; + const void *data = NULL; + void *data_dec; + Eet_Free_Context context; + int required_free = 0; + int size; + + ed = eet_dictionary_get(ef); + + if (!cipher_key) + data = eet_read_direct(ef, name, &size); + + if (!data) + { + required_free = 1; + data = eet_read_cipher(ef, name, &size, cipher_key); + if (!data) + return NULL; + } + + eet_free_context_init(&context); + data_dec = _eet_data_descriptor_decode(&context, ed, edd, data, size, NULL, 0); + eet_free_context_shutdown(&context); + + if (required_free) + free((void *)data); + + return data_dec; +} /* eet_data_read_cipher */ + +EAPI Eet_Node * +eet_data_node_read_cipher(Eet_File *ef, + const char *name, + const char *cipher_key) +{ + const Eet_Dictionary *ed = NULL; + const void *data = NULL; + Eet_Node *result; + Eet_Free_Context context; + int required_free = 0; + int size; + + ed = eet_dictionary_get(ef); + + if (!cipher_key) + data = eet_read_direct(ef, name, &size); + + if (!data) + { + required_free = 1; + data = eet_read_cipher(ef, name, &size, cipher_key); + if (!data) + return NULL; + } + + eet_free_context_init(&context); + result = _eet_data_descriptor_decode(&context, ed, NULL, data, size, NULL, 0); + eet_free_context_shutdown(&context); + + if (required_free) + free((void *)data); + + return result; +} /* eet_data_node_read_cipher */ + +EAPI void * +eet_data_read(Eet_File *ef, + Eet_Data_Descriptor *edd, + const char *name) +{ + return eet_data_read_cipher(ef, edd, name, NULL); +} /* eet_data_read */ + +EAPI int +eet_data_write_cipher(Eet_File *ef, + Eet_Data_Descriptor *edd, + const char *name, + const char *cipher_key, + const void *data, + int compress) +{ + Eet_Dictionary *ed; + void *data_enc; + int size; + int val; + + ed = eet_dictionary_get(ef); + + data_enc = _eet_data_descriptor_encode(ed, edd, data, &size); + if (!data_enc) + return 0; + + val = eet_write_cipher(ef, name, data_enc, size, compress, cipher_key); + free(data_enc); + return val; +} /* eet_data_write_cipher */ + +EAPI int +eet_data_write(Eet_File *ef, + Eet_Data_Descriptor *edd, + const char *name, + const void *data, + int compress) +{ + return eet_data_write_cipher(ef, edd, name, NULL, data, compress); +} /* eet_data_write */ + +static void +eet_free_context_init(Eet_Free_Context *context) +{ + unsigned int i = 0; + + memset(context, 0, sizeof (Eet_Free_Context)); + for (i = 0; i < EET_FREE_COUNT; ++i) + { + eina_array_step_set(&context->freelist.list[i], + sizeof (context->freelist.list[i]), + 32); + eina_array_step_set(&context->freelist_array.list[i], + sizeof (context->freelist.list[i]), + 32); + eina_array_step_set(&context->freelist_list.list[i], + sizeof (context->freelist.list[i]), + 32); + eina_array_step_set(&context->freelist_hash.list[i], + sizeof (context->freelist.list[i]), + 32); + eina_array_step_set(&context->freelist_str.list[i], + sizeof (context->freelist.list[i]), + 32); + eina_array_step_set(&context->freelist_direct_str.list[i], + sizeof (context->freelist.list[i]), + 32); + } +} + +static void +eet_free_context_shutdown(Eet_Free_Context *context) +{ + unsigned int i = 0; + + for (i = 0; i < EET_FREE_COUNT; ++i) + { + eina_array_flush(&context->freelist.list[i]); + eina_array_flush(&context->freelist_array.list[i]); + eina_array_flush(&context->freelist_list.list[i]); + eina_array_flush(&context->freelist_hash.list[i]); + eina_array_flush(&context->freelist_str.list[i]); + eina_array_flush(&context->freelist_direct_str.list[i]); + } +} + +static int +_eet_free_hash(void *data) +{ +#ifdef _WIN64 + __int64 ptr = (UINT_PTR)data; +#else /* ifdef _WIN64 */ + unsigned long ptr = (unsigned long)(data); +#endif /* ifdef _WIN64 */ + int hash; + + hash = ptr; + hash ^= ptr >> 8; + hash ^= ptr >> 16; + hash ^= ptr >> 24; + +#if defined (_WIN64) || ((!defined (_WIN32)) && (LONG_BIT != 32)) + hash ^= ptr >> 32; + hash ^= ptr >> 40; + hash ^= ptr >> 48; + hash ^= ptr >> 56; +#endif /* if defined (_WIN64) || ((!defined (_WIN32)) && (LONG_BIT != 32)) */ + + return hash & 0xFF; +} /* _eet_free_hash */ + +static void +_eet_free_add(Eet_Free *ef, + void *data) +{ + void *track; + Eina_Array_Iterator it; + unsigned int i; + int hash; + + hash = _eet_free_hash(data); + + EINA_ARRAY_ITER_NEXT(&ef->list[hash], i, track, it) + if (track == data) + return; + + eina_array_push(&ef->list[hash], data); +} /* _eet_free_add */ + +#if 0 +static void +_eet_free_del(Eet_Free *ef, + void *data) +{ + void *track; + Eina_Array_Iterator it; + unsigned int i; + int hash; + + hash = _eet_free_hash(data); + + EINA_ARRAY_ITER_NEXT(&ef->list[hash], i, track, it) + if (track == data) + { + eina_array_data_set(&ef->list[hash], i, NULL); + return; + } +} + +#endif + +static void +_eet_free_reset(Eet_Free *ef) +{ + unsigned int i; + + if (ef->ref > 0) + return; + + for (i = 0; i < EET_FREE_COUNT; ++i) + eina_array_clean(&ef->list[i]); +} /* _eet_free_reset */ + +static void +_eet_free_ref(Eet_Free *ef) +{ + ef->ref++; +} /* _eet_free_ref */ + +static void +_eet_free_unref(Eet_Free *ef) +{ + ef->ref--; +} /* _eet_free_unref */ + +#define _eet_freelist_add(Ctx, Data) _eet_free_add(&Ctx->freelist, Data); +#define _eet_freelist_del(Ctx, Data) _eet_free_del(&Ctx->freelist, Data); +#define _eet_freelist_reset(Ctx) _eet_free_reset(&Ctx->freelist); +#define _eet_freelist_ref(Ctx) _eet_free_ref(&Ctx->freelist); +#define _eet_freelist_unref(Ctx) _eet_free_unref(&Ctx->freelist); + +static void +_eet_freelist_free(Eet_Free_Context *context, + Eet_Data_Descriptor *edd) +{ + void *track; + Eina_Array_Iterator it; + unsigned int j; + unsigned int i; + + if (context->freelist.ref > 0) + return; + + for (j = 0; j < EET_FREE_COUNT; ++j) + EINA_ARRAY_ITER_NEXT(&context->freelist.list[j], i, track, it) + if (track) + { + if (edd) + edd->func.mem_free(track); + else + free(track); + } + _eet_free_reset(&context->freelist); +} /* _eet_freelist_free */ + +#define _eet_freelist_array_add(Ctx, Data) _eet_free_add(&Ctx->freelist_array, Data); +#define _eet_freelist_array_del(Ctx, Data) _eet_free_del(&Ctx->freelist_array, Data); +#define _eet_freelist_array_reset(Ctx) _eet_free_reset(&Ctx->freelist_array); +#define _eet_freelist_array_ref(Ctx) _eet_free_ref(&Ctx->freelist_array); +#define _eet_freelist_array_unref(Ctx) _eet_free_unref(&Ctx->freelist_array); + +static void +_eet_freelist_array_free(Eet_Free_Context *context, + Eet_Data_Descriptor *edd) +{ + void *track; + Eina_Array_Iterator it; + unsigned int j; + unsigned int i; + + if (context->freelist_array.ref > 0) + return; + + for (j = 0; j < EET_FREE_COUNT; ++j) + EINA_ARRAY_ITER_NEXT(&context->freelist_array.list[j], i, track, it) + if (track) + { + if (edd) + { + if (edd->func.array_free) + edd->func.array_free(track); + else + edd->func.mem_free(track); + } + else + free(track); + } + _eet_free_reset(&context->freelist_array); +} /* _eet_freelist_array_free */ + +#define _eet_freelist_list_add(Ctx, Data) _eet_free_add(&Ctx->freelist_list, Data); +#define _eet_freelist_list_del(Ctx, Data) _eet_free_del(&Ctx->freelist_list, Data); +#define _eet_freelist_list_reset(Ctx) _eet_free_reset(&Ctx->freelist_list); +#define _eet_freelist_list_ref(Ctx) _eet_free_ref(&Ctx->freelist_list); +#define _eet_freelist_list_unref(Ctx) _eet_free_unref(&Ctx->freelist_list); + +static void +_eet_freelist_list_free(Eet_Free_Context *context, + Eet_Data_Descriptor *edd) +{ + void *track; + Eina_Array_Iterator it; + unsigned int j; + unsigned int i; + + if (context->freelist_list.ref > 0) + return; + + for (j = 0; j < EET_FREE_COUNT; ++j) + EINA_ARRAY_ITER_NEXT(&context->freelist_list.list[j], i, track, it) + if (track) + { + if (edd) + edd->func.list_free(*((void **)(track))); + } + _eet_free_reset(&context->freelist_list); +} /* _eet_freelist_list_free */ + +#define _eet_freelist_str_add(Ctx, Data) _eet_free_add(&Ctx->freelist_str, Data); +#define _eet_freelist_str_del(Ctx, Data) _eet_free_del(&Ctx->freelist_str, Data); +#define _eet_freelist_str_reset(Ctx) _eet_free_reset(&Ctx->freelist_str); +#define _eet_freelist_str_ref(Ctx) _eet_free_ref(&Ctx->freelist_str); +#define _eet_freelist_str_unref(Ctx) _eet_free_unref(&Ctx->freelist_str); + +static void +_eet_freelist_str_free(Eet_Free_Context *context, + Eet_Data_Descriptor *edd) +{ + void *track; + Eina_Array_Iterator it; + unsigned int j; + unsigned int i; + + if (context->freelist_str.ref > 0) + return; + + for (j = 0; j < EET_FREE_COUNT; ++j) + EINA_ARRAY_ITER_NEXT(&context->freelist_str.list[j], i, track, it) + if (track) + { + if (edd) + edd->func.str_free(track); + else + free(track); + } + _eet_free_reset(&context->freelist_str); +} /* _eet_freelist_str_free */ + +#define _eet_freelist_direct_str_add(Ctx, Data) _eet_free_add(&Ctx->freelist_direct_str, Data); +#define _eet_freelist_direct_str_del(Ctx, Data) _eet_free_del(&Ctx->freelist_direct_str, Data); +#define _eet_freelist_direct_str_reset(Ctx) _eet_free_reset(&Ctx->freelist_direct_str); +#define _eet_freelist_direct_str_ref(Ctx) _eet_free_ref(&Ctx->freelist_direct_str); +#define _eet_freelist_direct_str_unref(Ctx) _eet_free_unref(&Ctx->freelist_direct_str); + +static void +_eet_freelist_direct_str_free(Eet_Free_Context *context, + Eet_Data_Descriptor *edd) +{ + void *track; + Eina_Array_Iterator it; + unsigned int j; + unsigned int i; + + if (context->freelist_direct_str.ref > 0) + return; + + for (j = 0; j < EET_FREE_COUNT; ++j) + EINA_ARRAY_ITER_NEXT(&context->freelist_str.list[j], i, track, it) + if (track) + { + if (edd) + edd->func.str_direct_free(track); + else + free(track); + } + _eet_free_reset(&context->freelist_direct_str); +} /* _eet_freelist_direct_str_free */ + +#define _eet_freelist_hash_add(Ctx, Data) _eet_free_add(&Ctx->freelist_hash, Data); +#define _eet_freelist_hash_del(Ctx, Data) _eet_free_del(&Ctx->freelist_hash, Data); +#define _eet_freelist_hash_reset(Ctx) _eet_free_reset(&Ctx->freelist_hash); +#define _eet_freelist_hash_ref(Ctx) _eet_free_ref(&Ctx->freelist_hash); +#define _eet_freelist_hash_unref(Ctx) _eet_free_unref(&Ctx->freelist_hash); + +static void +_eet_freelist_hash_free(Eet_Free_Context *context, + Eet_Data_Descriptor *edd) +{ + void *track; + Eina_Array_Iterator it; + unsigned int j; + unsigned int i; + + if (context->freelist_hash.ref > 0) + return; + + for (j = 0; j < EET_FREE_COUNT; ++j) + EINA_ARRAY_ITER_NEXT(&context->freelist_hash.list[j], i, track, it) + if (track) + { + if (edd) + edd->func.hash_free(track); + else + free(track); + } + _eet_free_reset(&context->freelist_hash); +} /* _eet_freelist_hash_free */ + +static void +_eet_freelist_all_ref(Eet_Free_Context *freelist_context) +{ + _eet_freelist_ref(freelist_context); + _eet_freelist_str_ref(freelist_context); + _eet_freelist_list_ref(freelist_context); + _eet_freelist_hash_ref(freelist_context); + _eet_freelist_direct_str_ref(freelist_context); +} /* _eet_freelist_all_ref */ + +static void +_eet_freelist_all_unref(Eet_Free_Context *freelist_context) +{ + _eet_freelist_unref(freelist_context); + _eet_freelist_str_unref(freelist_context); + _eet_freelist_list_unref(freelist_context); + _eet_freelist_hash_unref(freelist_context); + _eet_freelist_direct_str_unref(freelist_context); +} /* _eet_freelist_all_unref */ + +static int +eet_data_descriptor_encode_hash_cb(void *hash __UNUSED__, + const char *cipher_key, + void *hdata, + void *fdata) +{ + Eet_Dictionary *ed; + Eet_Data_Encode_Hash_Info *edehi; + Eet_Data_Stream *ds; + Eet_Data_Element *ede; + Eet_Data_Chunk *echnk; + void *data = NULL; + int size; + + edehi = fdata; + ede = edehi->ede; + ds = edehi->ds; + ed = edehi->ed; + + /* Store key */ + data = eet_data_put_type(ed, + EET_T_STRING, + &cipher_key, + &size); + if (data) + { + echnk = eet_data_chunk_new(data, + size, + ede->name, + ede->type, + ede->group_type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); + data = NULL; + } + + EET_ASSERT(!((ede->type > EET_T_UNKNOW) && (ede->type < EET_T_STRING)), return ); + + /* Store data */ + if (ede->type >= EET_T_STRING) + eet_data_put_unknown(ed, NULL, ede, ds, &hdata); + else + { + if (ede->subtype) + data = _eet_data_descriptor_encode(ed, + ede->subtype, + hdata, + &size); + + if (data) + { + echnk = eet_data_chunk_new(data, + size, + ede->name, + ede->type, + ede->group_type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); + data = NULL; + } + } + + return 1; +} /* eet_data_descriptor_encode_hash_cb */ + +static char * +_eet_data_dump_token_get(const char *src, + int *len) +{ + const char *p; + char *tok = NULL; + int in_token = 0; + int in_quote = 0; + int tlen = 0, tsize = 0; + +#define TOK_ADD(x) \ + do { \ + tlen++; \ + if (tlen >= tsize) \ + { \ + tsize += 32; \ + tok = realloc(tok, tsize); \ + } \ + tok[tlen - 1] = x; \ + } while (0) + + for (p = src; *len > 0; p++, (*len)--) + { + if (in_token) + { + if (in_quote) + { + if ((p[0] == '\"') && (p > src) && (p[-1] != '\\')) + in_quote = 0; + else if ((p[0] == '\\') && (*len > 1) && + (p[1] == '\"')) + { +/* skip */ + } + else if ((p[0] == '\\') && (p > src) && (p[-1] == '\\')) + { +/* skip */ + } + else if ((p[0] == '\\') && (*len > 1) && (p[1] == 'n')) + { +/* skip */ + } + else if ((p[0] == 'n') && (p > src) && (p[-1] == '\\')) + TOK_ADD('\n'); + else + TOK_ADD(p[0]); + } + else + { + if (p[0] == '\"') + in_quote = 1; + else + { + if ((isspace(p[0])) || (p[0] == ';')) /* token ends here */ + { + TOK_ADD(0); + (*len)--; + return tok; + } + else + TOK_ADD(p[0]); + } + } + } + else if (!((isspace(p[0])) || (p[0] == ';'))) + { + in_token = 1; + (*len)++; + p--; + } + } + if (in_token) + { + TOK_ADD(0); + return tok; + } + + if (tok) + free(tok); + + return NULL; +} /* _eet_data_dump_token_get */ + +static void +eet_data_encode(Eet_Dictionary *ed, + Eet_Data_Stream *ds, + void *data, + const char *name, + int size, + int type, + int group_type) +{ + Eet_Data_Chunk *echnk; + + if (!data) + type = EET_T_NULL; + + if (group_type != EET_G_UNKNOWN) + if (type >= EET_T_LAST) + type = EET_T_UNKNOW; + + echnk = eet_data_chunk_new(data, size, name, type, group_type); + eet_data_chunk_put(ed, echnk, ds); + eet_data_chunk_free(echnk); + free(data); +} /* eet_data_encode */ + +static void * +_eet_data_dump_encode(int parent_type, + Eet_Dictionary *ed, + Eet_Node *node, + int *size_ret) +{ + Eet_Data_Chunk *chnk = NULL; + Eet_Data_Stream *ds; + void *cdata, *data; + int csize, size; + int count; + int child_type; + Eet_Node *n; + + if (_eet_data_words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) + _eet_data_words_bigendian = 1; + else + _eet_data_words_bigendian = 0; + } + + if (!node) + return NULL; + + ds = eet_data_stream_new(); + if (!ds) + return NULL; + + switch (node->type) + { + case EET_G_UNKNOWN: + for (n = node->values; n; n = n->next) + { + data = _eet_data_dump_encode(node->type, ed, n, &size); + if (data) + { + eet_data_stream_write(ds, data, size); + free(data); + } + } + break; + + case EET_G_ARRAY: + case EET_G_VAR_ARRAY: + for (child_type = EET_T_NULL, n = node->values; n; n = n->next) + { + if (n->type != EET_T_NULL) + { + child_type = n->type; + break; + } + } + + data = eet_data_put_type(ed, + EET_T_INT, + &node->count, + &size); + eet_data_encode(ed, + ds, + data, + node->name, + size, + child_type, + node->type); + + count = node->count; + + for (n = node->values; n; n = n->next) + { + int pos = ds->pos; + + switch (n->type) + { + case EET_T_STRING: + case EET_T_INLINED_STRING: + data = eet_data_put_type(ed, + n->type, + &(n->data.value.str), + &size); + if (data) + eet_data_encode(ed, + ds, + data, + node->name, + size, + n->type, + node->type); + + break; + + case EET_T_NULL: + continue; + + default: + data = _eet_data_dump_encode(n->type, ed, n, &size); + eet_data_encode(ed, + ds, + data, + node->name, + size, + n->type, + node->type); + break; + } /* switch */ + if (ds->pos != pos) + count--; + } + + for (; count; count--) + { + eet_data_encode(ed, + ds, + NULL, + node->name, + 0, + EET_T_NULL, + node->type); + } + + /* Array is somekind of special case, so we should embed it inside another chunk. */ + *size_ret = ds->pos; + cdata = ds->data; + + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + + return cdata; + break; + + case EET_G_LIST: + for (n = node->values; n; n = n->next) + { + switch (n->type) + { + case EET_T_STRING: + case EET_T_INLINED_STRING: + data = eet_data_put_type(ed, + n->type, + &(n->data.value.str), + &size); + if (data) + eet_data_encode(ed, + ds, + data, + node->name, + size, + n->type, + node->type); + + break; + + case EET_T_NULL: + continue; + + default: + data = _eet_data_dump_encode(node->type, ed, n, &size); + eet_data_encode(ed, + ds, + data, + node->name, + size, + n->type, + node->type); + } /* switch */ + } + + /* List is another somekind of special case, every chunk is embed inside a list chunk. */ + *size_ret = ds->pos; + cdata = ds->data; + + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + + return cdata; + break; + + case EET_G_HASH: + if (node->key) + { + data = eet_data_put_type(ed, + EET_T_STRING, + &node->key, + &size); + eet_data_encode(ed, + ds, + data, + node->name, + size, + node->type, + node->type); + } + else + /* A Hash without key will not decode correctly. */ + return NULL; + + for (n = node->values; n; n = n->next) + { + switch (n->type) + { + case EET_T_STRING: + case EET_T_INLINED_STRING: + data = eet_data_put_type(ed, + n->type, + &(n->data.value.str), + &size); + if (data) + eet_data_encode(ed, + ds, + data, + node->name, + size, + n->type, + node->type); + + break; + + case EET_T_NULL: + continue; + + default: + data = _eet_data_dump_encode(node->type, ed, n, &size); + eet_data_encode(ed, + ds, + data, + node->name, + size, + n->type, + node->type); + } /* switch */ + } + + /* Hash is somekind of special case, so we should embed it inside another chunk. */ + *size_ret = ds->pos; + cdata = ds->data; + + eet_data_stream_flush(ds); + + return cdata; + + case EET_T_NULL: + break; + +#define EET_DATA_NODE_ENCODE(Eet_Type, Type) \ +case Eet_Type: \ + data = eet_data_put_type(ed, node->type, &(node->data.value.Type), &size); \ + if (data) \ + { \ + eet_data_encode(ed, \ + ds, \ + data, \ + node->name, \ + size, \ + node->type, \ + parent_type); \ + cdata = ds->data; \ + *size_ret = ds->pos; \ + eet_data_stream_flush(ds); \ + return cdata; \ + } /* switch */ \ + break; + + EET_DATA_NODE_ENCODE(EET_T_CHAR, c); + EET_DATA_NODE_ENCODE(EET_T_SHORT, s); + EET_DATA_NODE_ENCODE(EET_T_INT, i); + EET_DATA_NODE_ENCODE(EET_T_LONG_LONG, l); + EET_DATA_NODE_ENCODE(EET_T_FLOAT, f); + EET_DATA_NODE_ENCODE(EET_T_DOUBLE, d); + EET_DATA_NODE_ENCODE(EET_T_UCHAR, uc); + EET_DATA_NODE_ENCODE(EET_T_USHORT, us); + EET_DATA_NODE_ENCODE(EET_T_UINT, ui); + EET_DATA_NODE_ENCODE(EET_T_ULONG_LONG, ul); + EET_DATA_NODE_ENCODE(EET_T_INLINED_STRING, str); + EET_DATA_NODE_ENCODE(EET_T_STRING, str); + + default: + break; + } + + if ((node->type >= EET_G_UNKNOWN) && (node->type < EET_G_LAST)) + chnk = eet_data_chunk_new(ds->data, + ds->pos, + node->name, + EET_T_UNKNOW, + node->type); + else + chnk = eet_data_chunk_new(ds->data, + ds->pos, + node->name, + node->type, + EET_G_UNKNOWN); + + eet_data_stream_flush(ds); + + ds = eet_data_stream_new(); + eet_data_chunk_put(ed, chnk, ds); + cdata = ds->data; + csize = ds->pos; + + eet_data_stream_flush(ds); + *size_ret = csize; + + free(chnk->data); + eet_data_chunk_free(chnk); + + return cdata; +} /* _eet_data_dump_encode */ + +static void * +_eet_data_dump_parse(Eet_Dictionary *ed, + int *size_ret, + const char *src, + int size) +{ + void *cdata = NULL; + const char *p = NULL; +#define M_NONE 0 +#define M_STRUCT 1 +#define M_ 2 + int left, jump; + Eet_Node *node_base = NULL; + Eet_Node *node = NULL; + Eet_Node *n = NULL, *nn = NULL; + + /* FIXME; handle parse errors */ +#define TOK_GET(t) \ + jump = left; t = _eet_data_dump_token_get(p, &left); p += jump - left; + left = size; + for (p = src; p < (src + size); ) + { + char *tok1, *tok2, *tok3, *tok4; + + TOK_GET(tok1); + if (tok1) + { + if (!strcmp(tok1, "group")) + { + TOK_GET(tok2); + if (tok2) + { + TOK_GET(tok3); + if (tok3) + { + TOK_GET(tok4); + if (tok4) + { + if (!strcmp(tok4, "{")) + { +/* we have 'group NAM TYP {' */ + n = eet_node_new(); + if (n) + { + n->parent = node; + if (!node_base) + node_base = n; + + if (node) + { +/* append node */ + if (!node->values) + node->values = n; + else + for (nn = node->values; nn; + nn = nn->next) + { + if (!nn->next) + { + nn->next = n; + break; + } + } + } + + n->name = eina_stringshare_add(tok2); + if (!strcmp(tok3, "struct")) + n->type = EET_G_UNKNOWN; + else if (!strcmp(tok3, "array")) + n->type = EET_G_ARRAY; + else if (!strcmp(tok3, "var_array")) + n->type = EET_G_VAR_ARRAY; + else if (!strcmp(tok3, "list")) + n->type = EET_G_LIST; + else if (!strcmp(tok3, "hash")) + n->type = EET_G_HASH; + else + ERR( + "ERROR: group type '%s' invalid.", + tok3); + + node = n; + } + } + + free(tok4); + } + + free(tok3); + } + + free(tok2); + } + } + else if (!strcmp(tok1, "value")) + { + TOK_GET(tok2); + if (tok2) + { + TOK_GET(tok3); + if (tok3) + { + TOK_GET(tok4); + if (tok4) + { +/* we have 'value NAME TYP XXX' */ + if (node_base) + { + n = eet_node_new(); + if (n) + { + n->parent = node; +/* append node */ + if (!node->values) + node->values = n; + else + for (nn = node->values; nn; + nn = nn->next) + { + if (!nn->next) + { + nn->next = n; + break; + } + } + + n->name = eina_stringshare_add(tok2); + if (!strcmp(tok3, "char:")) + { + n->type = EET_T_CHAR; + sscanf(tok4, FMT_CHAR, + &(n->data.value.c)); + } + else if (!strcmp(tok3, "short:")) + { + n->type = EET_T_SHORT; + sscanf(tok4, "%hi", + &(n->data.value.s)); + } + else if (!strcmp(tok3, "int:")) + { + n->type = EET_T_INT; + sscanf(tok4, "%i", + &(n->data.value.i)); + } + else if (!strcmp(tok3, "long_long:")) + { + n->type = EET_T_LONG_LONG; + sscanf(tok4, FMT_LONG_LONG, + &(n->data.value.l)); + } + else if (!strcmp(tok3, "float:")) + { + n->type = EET_T_FLOAT; + sscanf(tok4, "%f", + &(n->data.value.f)); + } + else if (!strcmp(tok3, "double:")) + { + n->type = EET_T_DOUBLE; + sscanf(tok4, "%lf", + &(n->data.value.d)); + } + else if (!strcmp(tok3, "uchar:")) + { + n->type = EET_T_UCHAR; + sscanf(tok4, FMT_UCHAR, + &(n->data.value.uc)); + } + else if (!strcmp(tok3, "ushort:")) + { + n->type = EET_T_USHORT; + sscanf(tok4, "%hu", + &(n->data.value.us)); + } + else if (!strcmp(tok3, "uint:")) + { + n->type = EET_T_UINT; + sscanf(tok4, "%u", + &(n->data.value.ui)); + } + else if (!strcmp(tok3, "ulong_long:")) + { + n->type = EET_T_ULONG_LONG; + sscanf(tok4, FMT_ULONG_LONG, + &(n->data.value.ul)); + } + else if (!strcmp(tok3, "string:")) + { + n->type = EET_T_STRING; + n->data.value.str = + eina_stringshare_add(tok4); + } + else if (!strcmp(tok3, "inlined:")) + { + n->type = EET_T_INLINED_STRING; + n->data.value.str = + eina_stringshare_add(tok4); + } + else if (!strcmp(tok3, "null")) + { + n->type = EET_T_NULL; + n->data.value.str = NULL; + } + else + ERR( + "ERROR: value type '%s' invalid.", + tok4); + } + } + + free(tok4); + } + + free(tok3); + } + + free(tok2); + } + } + else if (!strcmp(tok1, "key")) + { + TOK_GET(tok2); + if (tok2) + { +/* we have 'key NAME' */ + if (node) + node->key = eina_stringshare_add(tok2); + + free(tok2); + } + } + else if (!strcmp(tok1, "count")) + { + TOK_GET(tok2); + if (tok2) + { +/* we have a 'count COUNT' */ + if (node) + sscanf(tok2, "%i", &(node->count)); + + free(tok2); + } + } + else if (!strcmp(tok1, "}")) + /* we have an end of the group */ + if (node) + node = node->parent; + + free(tok1); + } + } + + if (node_base) + { + cdata = _eet_data_dump_encode(EET_G_UNKNOWN, ed, node_base, size_ret); + eet_node_del(node_base); + } + + return cdata; +} /* _eet_data_dump_parse */ + +#define NEXT_CHUNK(P, Size, Echnk, Ed) \ + { \ + int __tmp; \ + __tmp = Ed ? (int)(sizeof(int) * 2) : Echnk.len + 4; \ + P += (4 + Echnk.size + __tmp); \ + Size -= (4 + Echnk.size + __tmp); \ + } + +static void * +_eet_data_descriptor_decode(Eet_Free_Context *context, + const Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + const void *data_in, + int size_in, + void *data_out, + int size_out) +{ + Eet_Node *result = NULL; + void *data = NULL; + char *p; + int size, i; + Eet_Data_Chunk chnk; + + if (_eet_data_words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) + _eet_data_words_bigendian = 1; + else + _eet_data_words_bigendian = 0; + } + + if (edd) + { + if (data_out) + { + if (size_out <= edd->size) + data = data_out; + } + else + { + data = edd->func.mem_alloc(edd->size); + } + + if (!data) + return NULL; + + if (edd->ed != ed) + { + for (i = 0; i < edd->elements.num; i++) + edd->elements.set[i].directory_name_ptr = NULL; + edd->ed = ed; + } + } + + _eet_freelist_all_ref(context); + if (data && !data_out) + _eet_freelist_add(context, data); + + memset(&chnk, 0, sizeof(Eet_Data_Chunk)); + eet_data_chunk_get(ed, &chnk, data_in, size_in); + if (!chnk.name) + goto error; + + if (edd) + if (strcmp(chnk.name, edd->name)) + goto error; + + p = chnk.data; + if (ed) + size = size_in - (4 + sizeof(int) * 2); + else + size = size_in - (4 + 4 + chnk.len); + + if (edd) + { + if (!edd->elements.hash.buckets) + _eet_descriptor_hash_new(edd); + } + else + { + switch (chnk.group_type) + { + case EET_G_UNKNOWN: + switch (chnk.type) + { + case EET_T_STRING: + return eet_node_string_new(chnk.name, chnk.data); + + case EET_T_INLINED_STRING: + return eet_node_inlined_string_new(chnk.name, chnk.data); + + case EET_T_NULL: + return eet_node_null_new(chnk.name); + + default: + result = eet_node_struct_new(chnk.name, NULL); + } /* switch */ + break; + + case EET_G_VAR_ARRAY: + return eet_node_var_array_new(chnk.name, NULL); + + case EET_G_LIST: + case EET_G_HASH: + case EET_G_ARRAY: + case EET_G_UNION: + case EET_G_VARIANT: + default: + goto error; + } /* switch */ + } + + while (size > 0) + { + Eet_Data_Chunk echnk; + Eet_Data_Element *ede = NULL; + Eet_Node *child = NULL; + int group_type = EET_G_UNKNOWN, type = EET_T_UNKNOW; + int ret = 0; + + /* get next data chunk */ + memset(&echnk, 0, sizeof(Eet_Data_Chunk)); + eet_data_chunk_get(ed, &echnk, p, size); + if (!echnk.name) + goto error; /* FIXME: don't REPLY on edd - work without */ + + if (edd) + { + ede = _eet_descriptor_hash_find(edd, echnk.name, echnk.hash); + if (ede) + { + group_type = ede->group_type; + type = ede->type; + if ((echnk.type == 0) && (echnk.group_type == 0)) + { + type = ede->type; + group_type = ede->group_type; + } + else + { + if (IS_SIMPLE_TYPE(echnk.type) && + eet_data_type_match(echnk.type, ede->type)) +/* Needed when converting on the fly from FP to Float */ + type = ede->type; + else if ((echnk.group_type > EET_G_UNKNOWN) && + (echnk.group_type < EET_G_LAST) && + (echnk.group_type == ede->group_type)) + group_type = echnk.group_type; + } + } + } + /*...... dump to node */ + else + { + type = echnk.type; + group_type = echnk.group_type; + } + + if (!edd && group_type == EET_G_UNKNOWN && IS_SIMPLE_TYPE(type)) + { + unsigned char dd[128]; + + ret = eet_data_get_type(ed, + type, + echnk.data, + ((char *)echnk.data) + echnk.size, + dd); + if (ret <= 0) + goto error; + + child = eet_data_node_simple_type(type, echnk.name, dd); + + eet_node_struct_append(result, echnk.name, child); + } + else + { + ret = eet_group_codec[group_type - 100].get( + context, + ed, + edd, + ede, + &echnk, + type, + group_type, + ede ? (void *)(((char *)data) + ede->offset) : (void **)&result, + &p, + &size); + + if (ret <= 0) + goto error; + } + + /* advance to next chunk */ + NEXT_CHUNK(p, size, echnk, ed); + } + + _eet_freelist_all_unref(context); + if (!edd) + { + _eet_freelist_str_free(context, edd); + _eet_freelist_direct_str_free(context, edd); + _eet_freelist_list_free(context, edd); + _eet_freelist_hash_free(context, edd); + _eet_freelist_array_free(context, edd); + _eet_freelist_free(context, edd); + } + else + { + _eet_freelist_reset(context); + _eet_freelist_str_reset(context); + _eet_freelist_list_reset(context); + _eet_freelist_hash_reset(context); + _eet_freelist_direct_str_reset(context); + _eet_freelist_array_reset(context); + } + + if (!edd) + return result; + + return data; + +error: + eet_node_del(result); + + _eet_freelist_all_unref(context); + _eet_freelist_str_free(context, edd); + _eet_freelist_direct_str_free(context, edd); + _eet_freelist_list_free(context, edd); + _eet_freelist_hash_free(context, edd); + _eet_freelist_array_free(context, edd); + _eet_freelist_free(context, edd); + + /* FIXME: Warn that something goes wrong here. */ + return NULL; +} /* _eet_data_descriptor_decode */ + +static int +eet_data_get_list(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 __UNUSED__, + void *data, + char **p, + int *size) +{ + Eet_Data_Descriptor *subtype = NULL; + void *list = NULL; + void **ptr; + void *data_ret; + + EET_ASSERT(!((type > EET_T_UNKNOW) && (type < EET_T_STRING)), return 0); + + if (ede) + { + subtype = ede->subtype; + + if (type != ede->type) + return 0; + } + + ptr = (void **)data; + list = *ptr; + data_ret = NULL; + + if (IS_POINTER_TYPE(type)) + POINTER_TYPE_DECODE(context, + ed, + edd, + ede, + echnk, + type, + &data_ret, + p, + size, + on_error); + else + STRUCT_TYPE_DECODE(data_ret, + context, + ed, + subtype, + echnk->data, + echnk->size, + -1, + on_error); + + if (edd) + { + list = edd->func.list_append(list, data_ret); + *ptr = list; + _eet_freelist_list_add(context, ptr); + } + else + eet_node_list_append(*((Eet_Node **)data), echnk->name, data_ret); + + return 1; + +on_error: + return 0; +} /* eet_data_get_list */ + +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 __UNUSED__, + void *data, + char **p, + int *size) +{ + void **ptr; + void *hash = NULL; + char *key = NULL; + void *data_ret = NULL; + int ret = 0; + + EET_ASSERT(!((type > EET_T_UNKNOW) && (type < EET_T_STRING)), return 0); + + ptr = (void **)data; + hash = *ptr; + + /* Read key */ + ret = eet_data_get_type(ed, + EET_T_STRING, + echnk->data, + ((char *)echnk->data) + echnk->size, + &key); + if (ret <= 0) + goto on_error; + + if (!key) + 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) + if ((ede->group_type != echnk->group_type) + || (ede->type != echnk->type)) + goto on_error; + + if (IS_POINTER_TYPE(echnk->type)) + POINTER_TYPE_DECODE(context, + ed, + edd, + ede, + echnk, + echnk->type, + &data_ret, + p, + size, + on_error); + else + STRUCT_TYPE_DECODE(data_ret, + context, + ed, + ede ? ede->subtype : NULL, + echnk->data, + echnk->size, + -1, + on_error); + + if (edd) + { + hash = edd->func.hash_add(hash, key, data_ret); + *ptr = hash; + _eet_freelist_hash_add(context, hash); + } + else + eet_node_hash_add(*((Eet_Node **)data), echnk->name, key, data_ret); + + return 1; + +on_error: + return 0; +} /* eet_data_get_hash */ + +/* var arrays and fixed arrays have to + * get all chunks at once. for fixed arrays + * we can get each chunk and increment a + * counter stored on the element itself but + * it wont be thread safe. for var arrays + * we still need a way to get the number of + * elements from the data, so storing the + * number of elements and the element data on + * each chunk is pointless. + */ +static int +eet_data_get_array(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) +{ + Eina_List *childs = NULL; + const char *name; + Eet_Node *tmp; + void *ptr; + int count; + int ret; + int subsize = 0; + int i; + + EET_ASSERT(!((type > EET_T_UNKNOW) && (type < EET_T_STRING)), return 0); + + ptr = data; + /* read the number of elements */ + ret = eet_data_get_type(ed, + EET_T_INT, + echnk->data, + ((char *)echnk->data) + echnk->size, + &count); + if (ret <= 0) + return ret; + + name = echnk->name; + + if (ede) + { + if (IS_POINTER_TYPE(type)) + subsize = eet_basic_codec[ede->type].size; + else + subsize = ede->subtype->size; + + if (group_type == EET_G_VAR_ARRAY) + { + /* store the number of elements + * on the counter offset */ + *(int *)(((char *)data) + ede->count - ede->offset) = count; + /* allocate space for the array of elements */ + if (edd->func.array_alloc) + *(void **)ptr = edd->func.array_alloc(count * subsize); + else + *(void **)ptr = edd->func.mem_alloc(count * subsize); + + if (!*(void **)ptr) + return 0; + + memset(*(void **)ptr, 0, count * subsize); + + _eet_freelist_array_add(context, *(void **)ptr); + } + } + + /* get all array elements */ + for (i = 0; i < count; i++) + { + void *dst = NULL; + + /* Advance to next chunk */ + NEXT_CHUNK((*p), (*size), (*echnk), ed); + memset(echnk, 0, sizeof(Eet_Data_Chunk)); + + eet_data_chunk_get(ed, echnk, *p, *size); + if (!echnk->name || strcmp(echnk->name, name) != 0) + goto on_error; /* get the data */ + + if ((echnk->group_type != group_type) + || ((echnk->type != type) && (echnk->type != EET_T_NULL))) + goto on_error; + + if (ede) + if ((ede->group_type != echnk->group_type) + || ((echnk->type != ede->type) && (echnk->type != EET_T_NULL))) + goto on_error; + + /* get the destination pointer */ + if (ede) + { + if (group_type == EET_G_ARRAY) + dst = (char *)ptr + (subsize * i); + else + dst = *(char **)ptr + (subsize * i); + } + + if (IS_POINTER_TYPE(echnk->type)) + { + void *data_ret = NULL; + + POINTER_TYPE_DECODE(context, + ed, + edd, + ede, + echnk, + echnk->type, + &data_ret, + p, + size, + on_error); + if (dst) + memcpy(dst, &data_ret, subsize); + + if (!edd) + childs = eina_list_append(childs, data_ret); + } + else + { + STRUCT_TYPE_DECODE(dst, + context, + ed, + ede ? ede->subtype : NULL, + echnk->data, + echnk->size, + subsize, + on_error); + + if (!edd) + childs = eina_list_append(childs, dst); + } + } + + if (!edd) + { + Eet_Node *parent = *((Eet_Node **)data); + Eet_Node *array; + + if (group_type == EET_G_ARRAY) + array = eet_node_array_new(name, count, childs); + else + array = eet_node_var_array_new(name, childs); + + if (!array) + goto on_error; + + eet_node_struct_append(parent, name, array); + } + + return 1; + +on_error: + EINA_LIST_FREE(childs, tmp) + eet_node_del(tmp); + + return 0; +} /* eet_data_get_array */ + +static void +eet_data_put_union(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd __UNUSED__, + 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; + } +} /* eet_data_put_union */ + +static int +eet_data_get_union(Eet_Free_Context *context, + const Eet_Dictionary *ed, + Eet_Data_Descriptor *edd __UNUSED__, + 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; + char *ut; + + /* 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, + data, + sede->subtype->size); + if (!data_ret) + goto on_error; + + /* Set union type. */ + if ((!ed) || (!ede->subtype->func.str_direct_alloc)) + { + ut = ede->subtype->func.str_alloc(union_type); + _eet_freelist_str_add(context, ut); + } + else + { + ut = ede->subtype->func.str_direct_alloc(union_type); + _eet_freelist_direct_str_add(context, ut); + } + + ede->subtype->func.type_set( + ut, + ((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, + NULL, 0); + goto on_error; + } + + return 1; + +on_error: + return 0; +} /* eet_data_get_union */ + +static void +eet_data_put_variant(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd __UNUSED__, + 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; + } +} /* eet_data_put_variant */ + +static int +eet_data_get_variant(Eet_Free_Context *context, + const Eet_Dictionary *ed, + Eet_Data_Descriptor *edd __UNUSED__, + Eet_Data_Element *ede, + Eet_Data_Chunk *echnk, + int type __UNUSED__, + int group_type __UNUSED__, + 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) + { + char *ut; + + EET_ASSERT(ede->subtype, goto on_error); + + if ((!ed) || (!ede->subtype->func.str_direct_alloc)) + { + ut = ede->subtype->func.str_alloc(union_type); + _eet_freelist_str_add(context, ut); + } + else + { + ut = ede->subtype->func.str_direct_alloc(union_type); + _eet_freelist_direct_str_add(context, ut); + } + + /* 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; + + 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 + (ut, ((char *)data) + ede->count - ede->offset, + EINA_FALSE); + break; + } + + data_ret = _eet_data_descriptor_decode(context, + ed, + sede->subtype, + echnk->data, + echnk->size, + NULL, 0); + if (!data_ret) + break; + + /* And point to the variant data. */ + *(void **)data = data_ret; + + /* Set variant type. */ + ede->subtype->func.type_set + (ut, ((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 + (ut, ((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, + NULL, 0); + goto on_error; + } + + return 1; + +on_error: + return 0; +} /* eet_data_get_variant */ + +static Eet_Node * +eet_data_node_simple_type(int type, + const char *name, + void *dd) +{ +#ifdef EET_T_TYPE +# undef EET_T_TYPE +#endif /* ifdef EET_T_TYPE */ + +#define EET_T_TYPE(Eet_Type, Eet_Node_Type, Type) \ +case Eet_Type: \ + return eet_node_ ## Eet_Node_Type ## _new(name, *((Type *)dd)); \ + + switch (type) + { + EET_T_TYPE(EET_T_CHAR, char, char); + EET_T_TYPE(EET_T_SHORT, short, short); + EET_T_TYPE(EET_T_INT, int, int); + EET_T_TYPE(EET_T_LONG_LONG, long_long, long long); + EET_T_TYPE(EET_T_FLOAT, float, float); + EET_T_TYPE(EET_T_DOUBLE, double, double); + EET_T_TYPE(EET_T_UCHAR, unsigned_char, unsigned char); + EET_T_TYPE(EET_T_USHORT, unsigned_short, unsigned short); + EET_T_TYPE(EET_T_UINT, unsigned_int, unsigned int); + EET_T_TYPE(EET_T_ULONG_LONG, unsigned_long_long, unsigned long long); + EET_T_TYPE(EET_T_STRING, string, char *); + EET_T_TYPE(EET_T_INLINED_STRING, inlined_string, char *); + + case EET_T_NULL: + return eet_node_null_new(name); + + default: + ERR("Unknow type passed to eet_data_node_simple_type"); + return NULL; + } /* switch */ +} /* eet_data_node_simple_type */ + +static int +eet_data_get_unknown(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 __UNUSED__, + void *data, + char **p __UNUSED__, + int *size __UNUSED__) +{ + int ret; + void *data_ret; + + if (IS_SIMPLE_TYPE(type)) + { + unsigned char dd[128]; + + ret = eet_data_get_type(ed, + type, + echnk->data, + ((char *)echnk->data) + echnk->size, + edd ? (char *)data : (char *)dd); + if (ret <= 0) + return ret; + + if (!edd) + { + Eet_Node **parent = data; + Eet_Node *node; + + node = eet_data_node_simple_type(type, echnk->name, dd); + + if (*parent) + eet_node_struct_append(*parent, echnk->name, node); + else + *parent = node; + } + else + { + if (type == EET_T_STRING) + { + char **str; + + str = (char **)(((char *)data)); + if (*str) + { + if ((!ed) || (!edd->func.str_direct_alloc)) + { + *str = edd->func.str_alloc(*str); + _eet_freelist_str_add(context, *str); + } + else + { + *str = edd->func.str_direct_alloc(*str); + _eet_freelist_direct_str_add(context, *str); + } + } + } + else if (edd && type == EET_T_INLINED_STRING) + { + char **str; + + str = (char **)(((char *)data)); + if (*str) + { + *str = edd->func.str_alloc(*str); + _eet_freelist_str_add(context, *str); + } + } + } + } + else + { + Eet_Data_Descriptor *subtype; + + subtype = ede ? ede->subtype : NULL; + + if (subtype || !edd) + { + Eet_Node **parent = data; + void **ptr; + + data_ret = _eet_data_descriptor_decode(context, + ed, + subtype, + echnk->data, + echnk->size, + NULL, 0); + if (!data_ret) + return 0; + + if (edd) + { + ptr = (void **)(((char *)data)); + *ptr = (void *)data_ret; + } + else + { + Eet_Node *node = data_ret; + + if (*parent) + { + node = eet_node_struct_child_new(echnk->name, node); + eet_node_struct_append(*parent, echnk->name, node); + } + else + *parent = node; + } + } + } + + return 1; +} /* eet_data_get_unknown */ + +static void +eet_data_put_array(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd __UNUSED__, + Eet_Data_Element *ede, + Eet_Data_Stream *ds, + void *data_in) +{ + void *data; + int offset = 0; + int subsize; + int count; + int size; + int j; + + EET_ASSERT(!((ede->type > EET_T_UNKNOW) && (ede->type < EET_T_STRING)), + return ); + + if (ede->group_type == EET_G_ARRAY) + count = ede->counter_offset; + else + count = *(int *)(((char *)data_in) + ede->count - ede->offset); + + if (count <= 0) + return; /* Store number of elements */ + + data = eet_data_put_type(ed, EET_T_INT, &count, &size); + if (data) + eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + + if (IS_POINTER_TYPE(ede->type)) + subsize = eet_basic_codec[ede->type].size; + else + subsize = ede->subtype->size; + + for (j = 0; j < count; j++) + { + void *d; + int pos = ds->pos; + + if (ede->group_type == EET_G_ARRAY) + d = (void *)(((char *)data_in) + offset); + else + d = *(((char **)data_in)) + offset; + + if (IS_POINTER_TYPE(ede->type)) + { + if (*(char **)d) + eet_data_put_unknown(ed, NULL, ede, ds, d); + } + else + { + data = _eet_data_descriptor_encode(ed, ede->subtype, d, &size); + if (data) + eet_data_encode(ed, + ds, + data, + ede->name, + size, + ede->type, + ede->group_type); + } + + if (pos == ds->pos) + /* Add a NULL element just to have the correct array layout. */ + eet_data_encode(ed, + ds, + NULL, + ede->name, + 0, + EET_T_NULL, + ede->group_type); + + offset += subsize; + } +} /* eet_data_put_array */ + +static void +eet_data_put_unknown(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd __UNUSED__, + Eet_Data_Element *ede, + Eet_Data_Stream *ds, + void *data_in) +{ + void *data = NULL; + int size; + + if (IS_SIMPLE_TYPE(ede->type)) + data = eet_data_put_type(ed, ede->type, data_in, &size); + else if (ede->subtype) + if (*((char **)data_in)) + data = _eet_data_descriptor_encode(ed, + ede->subtype, + *((char **)((char *)(data_in))), + &size); + + if (data) + eet_data_encode(ed, + ds, + data, + ede->name, + size, + ede->type, + ede->group_type); +} /* eet_data_put_unknown */ + +static void +eet_data_put_list(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, + Eet_Data_Stream *ds, + void *data_in) +{ + void *data; + void *l; + int size; + + EET_ASSERT(!(((ede->type > EET_T_UNKNOW) && (ede->type < EET_T_STRING)) + || ((ede->type > EET_T_NULL) && (ede->type < EET_T_LAST))), + return ); + + l = *((void **)(((char *)data_in))); + for (; l; l = edd->func.list_next(l)) + { + if (IS_POINTER_TYPE(ede->type)) + { + const void *str = edd->func.list_data(l); + eet_data_put_unknown(ed, NULL, ede, ds, &str); + } + else + { + data = _eet_data_descriptor_encode(ed, + ede->subtype, + edd->func.list_data(l), + &size); + if (data) + eet_data_encode(ed, + ds, + data, + ede->name, + size, + ede->type, + ede->group_type); + } + } +} /* eet_data_put_list */ + +static void +eet_data_put_hash(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, + Eet_Data_Stream *ds, + void *data_in) +{ + Eet_Data_Encode_Hash_Info fdata; + void *l; + + l = *((void **)(((char *)data_in))); + fdata.ds = ds; + fdata.ede = ede; + fdata.ed = ed; + edd->func.hash_foreach(l, eet_data_descriptor_encode_hash_cb, &fdata); +} /* eet_data_put_hash */ + +EAPI int +eet_data_dump_cipher(Eet_File *ef, + const char *name, + const char *cipher_key, + Eet_Dump_Callback dumpfunc, + void *dumpdata) +{ + const Eet_Dictionary *ed = NULL; + const void *data = NULL; + Eet_Node *result; + Eet_Free_Context context; + int required_free = 0; + int size; + + ed = eet_dictionary_get(ef); + + if (!cipher_key) + data = eet_read_direct(ef, name, &size); + + if (!data) + { + required_free = 1; + data = eet_read_cipher(ef, name, &size, cipher_key); + if (!data) + return 0; + } + + eet_free_context_init(&context); + result = _eet_data_descriptor_decode(&context, ed, NULL, data, size, NULL, 0); + eet_free_context_shutdown(&context); + + eet_node_dump(result, 0, dumpfunc, dumpdata); + + eet_node_del(result); + + if (required_free) + free((void *)data); + + return result ? 1 : 0; +} /* eet_data_dump_cipher */ + +EAPI int +eet_data_dump(Eet_File *ef, + const char *name, + Eet_Dump_Callback dumpfunc, + void *dumpdata) +{ + return eet_data_dump_cipher(ef, name, NULL, dumpfunc, dumpdata); +} /* eet_data_dump */ + +EAPI int +eet_data_text_dump_cipher(const void *data_in, + const char *cipher_key, + int size_in, + Eet_Dump_Callback dumpfunc, + void *dumpdata) +{ + void *ret = NULL; + Eet_Node *result; + Eet_Free_Context context; + unsigned int ret_len = 0; + + if (!data_in) + return 0; + + if (cipher_key) + { + if (eet_decipher(data_in, size_in, cipher_key, + strlen(cipher_key), &ret, &ret_len)) + { + if (ret) + free(ret); + + return 0; + } + } + else + { + ret = (void *)data_in; + ret_len = size_in; + } + + eet_free_context_init(&context); + result = _eet_data_descriptor_decode(&context, NULL, NULL, ret, ret_len, NULL, 0); + eet_free_context_shutdown(&context); + + eet_node_dump(result, 0, dumpfunc, dumpdata); + + eet_node_del(result); + if (cipher_key) + free(ret); + + return result ? 1 : 0; +} /* eet_data_text_dump_cipher */ + +EAPI int +eet_data_text_dump(const void *data_in, + int size_in, + Eet_Dump_Callback dumpfunc, + void *dumpdata) +{ + return eet_data_text_dump_cipher(data_in, NULL, size_in, dumpfunc, dumpdata); +} /* eet_data_text_dump */ + +EAPI void * +eet_data_text_undump_cipher(const char *text, + const char *cipher_key, + int textlen, + int *size_ret) +{ + void *ret = NULL; + + ret = _eet_data_dump_parse(NULL, size_ret, text, textlen); + if (ret && cipher_key) + { + void *ciphered = NULL; + unsigned int ciphered_len; + + if (eet_cipher(ret, *size_ret, cipher_key, + strlen(cipher_key), &ciphered, &ciphered_len)) + { + if (ciphered) + free(ciphered); + + size_ret = 0; + free(ret); + return NULL; + } + + free(ret); + *size_ret = ciphered_len; + ret = ciphered; + } + + return ret; +} /* eet_data_text_undump_cipher */ + +EAPI void * +eet_data_text_undump(const char *text, + int textlen, + int *size_ret) +{ + return eet_data_text_undump_cipher(text, NULL, textlen, size_ret); +} /* eet_data_text_undump */ + +EAPI int +eet_data_undump_cipher(Eet_File *ef, + const char *name, + const char *cipher_key, + const char *text, + int textlen, + int compress) +{ + Eet_Dictionary *ed; + void *data_enc; + int size; + int val; + + ed = eet_dictionary_get(ef); + + data_enc = _eet_data_dump_parse(ed, &size, text, textlen); + if (!data_enc) + return 0; + + val = eet_write_cipher(ef, name, data_enc, size, compress, cipher_key); + free(data_enc); + return val; +} /* eet_data_undump_cipher */ + +EAPI int +eet_data_undump(Eet_File *ef, + const char *name, + const char *text, + int textlen, + int compress) +{ + return eet_data_undump_cipher(ef, name, NULL, text, textlen, compress); +} /* eet_data_undump */ + +EAPI void * +eet_data_descriptor_decode_cipher(Eet_Data_Descriptor *edd, + const void *data_in, + const char *cipher_key, + int size_in) +{ + void *deciphered = (void *)data_in; + void *ret; + Eet_Free_Context context; + unsigned int deciphered_len = size_in; + + if (cipher_key && data_in) + if (eet_decipher(data_in, size_in, cipher_key, + strlen(cipher_key), &deciphered, &deciphered_len)) + { + if (deciphered) + free(deciphered); + + return NULL; + } + + eet_free_context_init(&context); + ret = _eet_data_descriptor_decode(&context, + NULL, + edd, + deciphered, + deciphered_len, + NULL, 0); + eet_free_context_shutdown(&context); + + if (data_in != deciphered) + free(deciphered); + + return ret; +} /* eet_data_descriptor_decode_cipher */ + +EAPI void * +eet_data_descriptor_decode(Eet_Data_Descriptor *edd, + const void *data_in, + int size_in) +{ + return eet_data_descriptor_decode_cipher(edd, data_in, NULL, size_in); +} /* eet_data_descriptor_decode */ + +EAPI Eet_Node * +eet_data_node_decode_cipher(const void *data_in, + const char *cipher_key, + int size_in) +{ + void *deciphered = (void *)data_in; + Eet_Node *ret; + Eet_Free_Context context; + unsigned int deciphered_len = size_in; + + if (cipher_key && data_in) + if (eet_decipher(data_in, size_in, cipher_key, + strlen(cipher_key), &deciphered, &deciphered_len)) + { + if (deciphered) + free(deciphered); + + return NULL; + } + + eet_free_context_init(&context); + ret = _eet_data_descriptor_decode(&context, + NULL, + NULL, + deciphered, + deciphered_len, + NULL, 0); + eet_free_context_shutdown(&context); + + if (data_in != deciphered) + free(deciphered); + + return ret; +} /* eet_data_node_decode_cipher */ + +static void * +_eet_data_descriptor_encode(Eet_Dictionary *ed, + Eet_Data_Descriptor *edd, + const void *data_in, + int *size_ret) +{ + Eet_Data_Stream *ds; + Eet_Data_Chunk *chnk; + void *cdata; + int csize; + int i; + + if (_eet_data_words_bigendian == -1) + { + unsigned long int v; + + v = htonl(0x12345678); + if (v == 0x12345678) + _eet_data_words_bigendian = 1; + else + _eet_data_words_bigendian = 0; + } + + ds = eet_data_stream_new(); + for (i = 0; i < edd->elements.num; i++) + { + Eet_Data_Element *ede; + + ede = &(edd->elements.set[i]); + eet_group_codec[ede->group_type - 100].put( + ed, + edd, + ede, + ds, + ((char *)data_in) + + ede->offset); + } + chnk = eet_data_chunk_new(ds->data, + ds->pos, + edd->name, + EET_T_UNKNOW, + EET_G_UNKNOWN); + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + + ds = eet_data_stream_new(); + eet_data_chunk_put(ed, chnk, ds); + cdata = ds->data; + csize = ds->pos; + + ds->data = NULL; + ds->size = 0; + eet_data_stream_free(ds); + *size_ret = csize; + + free(chnk->data); + eet_data_chunk_free(chnk); + + return cdata; +} /* _eet_data_descriptor_encode */ + +EAPI int +eet_data_node_write_cipher(Eet_File *ef, + const char *name, + const char *cipher_key, + Eet_Node *node, + int compress) +{ + Eet_Dictionary *ed; + void *data_enc; + int size; + int val; + + ed = eet_dictionary_get(ef); + + data_enc = _eet_data_dump_encode(EET_G_UNKNOWN, ed, node, &size); + if (!data_enc) + return 0; + + val = eet_write_cipher(ef, name, data_enc, size, compress, cipher_key); + free(data_enc); + return val; +} /* eet_data_node_write_cipher */ + +EAPI void * +eet_data_node_encode_cipher(Eet_Node *node, + const char *cipher_key, + int *size_ret) +{ + void *ret = NULL; + void *ciphered = NULL; + unsigned int ciphered_len = 0; + int size; + + ret = _eet_data_dump_encode(EET_G_UNKNOWN, NULL, node, &size); + if (cipher_key && ret) + { + if (eet_cipher(ret, size, cipher_key, + strlen(cipher_key), &ciphered, &ciphered_len)) + { + if (ciphered) + free(ciphered); + + if (size_ret) + *size_ret = 0; + + free(ret); + return NULL; + } + + free(ret); + size = (int)ciphered_len; + ret = ciphered; + } + + if (size_ret) + *size_ret = size; + + return ret; +} /* eet_data_node_encode_cipher */ + +EAPI void * +eet_data_descriptor_encode_cipher(Eet_Data_Descriptor *edd, + const void *data_in, + const char *cipher_key, + int *size_ret) +{ + void *ret = NULL; + void *ciphered = NULL; + unsigned int ciphered_len = 0; + int size; + + ret = _eet_data_descriptor_encode(NULL, edd, data_in, &size); + if (cipher_key && ret) + { + if (eet_cipher(ret, size, cipher_key, + strlen(cipher_key), &ciphered, &ciphered_len)) + { + if (ciphered) + free(ciphered); + + if (size_ret) + *size_ret = 0; + + free(ret); + return NULL; + } + + free(ret); + size = ciphered_len; + ret = ciphered; + } + + if (size_ret) + *size_ret = size; + + return ret; +} /* eet_data_descriptor_encode_cipher */ + +EAPI void * +eet_data_descriptor_encode(Eet_Data_Descriptor *edd, + const void *data_in, + int *size_ret) +{ + return eet_data_descriptor_encode_cipher(edd, data_in, NULL, size_ret); +} /* eet_data_descriptor_encode */ + +EAPI void * +eet_data_xattr_cipher_get(const char *filename, + const char *attribute, + Eet_Data_Descriptor *edd, + const char *cipher_key) +{ + void *blob; + void *ret; + ssize_t size; + + blob = eina_xattr_get(filename, attribute, &size); + if (!blob) return NULL; + + ret = eet_data_descriptor_decode_cipher(edd, blob, cipher_key, size); + free(blob); + + return ret; +} + +EAPI Eina_Bool +eet_data_xattr_cipher_set(const char *filename, + const char *attribute, + Eet_Data_Descriptor *edd, + const char *cipher_key, + const void *data, + Eina_Xattr_Flags flags) +{ + void *blob; + int size; + Eina_Bool ret; + + blob = eet_data_descriptor_encode_cipher(edd, data, cipher_key, &size); + if (!blob) return EINA_FALSE; + + ret = eina_xattr_set(filename, attribute, blob, size, flags); + free(blob); + + return ret; +} + -- cgit v1.1