efl/src/lib/eet/eet_data.c

5027 lines
144 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif /* ifdef HAVE_CONFIG_H */
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <ctype.h>
#include <limits.h>
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif /* ifdef HAVE_NETINET_IN_H */
#ifdef _WIN32
# include <winsock2.h>
#endif /* ifdef _WIN32 */
#include <Eina.h>
#include "Eet.h"
#include "Eet_private.h"
/*
* 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
{
const 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 EINA_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);
}
static void *
eet_data_put_char(Eet_Dictionary *ed EINA_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;
}
/* SHORT TYPE */
static int
eet_data_get_short(const Eet_Dictionary *ed EINA_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);
}
static void *
eet_data_put_short(Eet_Dictionary *ed EINA_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;
}
/* INT TYPE */
static inline int
eet_data_get_int(const Eet_Dictionary *ed EINA_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);
}
static void *
eet_data_put_int(Eet_Dictionary *ed EINA_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;
}
/* LONG LONG TYPE */
static int
eet_data_get_long_long(const Eet_Dictionary *ed EINA_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);
}
static void *
eet_data_put_long_long(Eet_Dictionary *ed EINA_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;
}
/* 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;
}
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;
}
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;
}
/* ALWAYS INLINED STRING TYPE */
static int
eet_data_get_istring(const Eet_Dictionary *ed EINA_UNUSED,
const void *src,
const void *src_end,
void *dst)
{
return eet_data_get_string(NULL, src, src_end, dst);
}
static void *
eet_data_put_istring(Eet_Dictionary *ed EINA_UNUSED,
const void *src,
int *size_ret)
{
return eet_data_put_string(NULL, src, size_ret);
}
/* ALWAYS NULL TYPE */
static int
eet_data_get_null(const Eet_Dictionary *ed EINA_UNUSED,
const void *src EINA_UNUSED,
const void *src_end EINA_UNUSED,
void *dst)
{
char **d;
d = (char **)dst;
*d = NULL;
return 1;
}
static void *
eet_data_put_null(Eet_Dictionary *ed EINA_UNUSED,
const void *src EINA_UNUSED,
int *size_ret)
{
*size_ret = 0;
return 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;
}
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;
}
/* 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;
}
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);
}
/* 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;
}
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);
}
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;
}
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);
}
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;
}
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);
}
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;
}
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);
}
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;
}
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;
}
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;
}
return EINA_FALSE;
}
/* 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;
}
}
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;
}
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 = name;
chnk->len = strlen(name) + 1;
chnk->size = size;
chnk->data = data;
chnk->type = type;
chnk->group_type = group_type;
return chnk;
}
static inline void
eet_data_chunk_free(Eet_Data_Chunk *chnk)
{
free(chnk);
}
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;
}
static inline void
eet_data_stream_free(Eet_Data_Stream *ds)
{
if (ds->data)
free(ds->data);
free(ds);
}
static inline void
eet_data_stream_flush(Eet_Data_Stream *ds)
{
free(ds);
}
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;
}
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;
}
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(size);
on_error:
free(string);
}
/*---*/
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;
}
}
}
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);
}
static Eet_Data_Element *
_eet_descriptor_hash_find(Eet_Data_Descriptor *edd,
const 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;
}
static void *
_eet_mem_alloc(size_t size)
{
return calloc(1, size);
}
static void
_eet_mem_free(void *mem)
{
free(mem);
}
static char *
_eet_str_alloc(const char *str)
{
return strdup(str);
}
static void
_eet_str_free(const char *str)
{
free((char *)str);
}
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;
}
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;
}
static char *
_eet_str_direct_alloc(const char *str)
{
return (char *)str;
}
static void
_eet_str_direct_free(const char *str EINA_UNUSED)
{
}
static void
_eet_eina_hash_foreach(void *hash,
Eina_Hash_Foreach cb,
void *fdata)
{
if (hash)
eina_hash_foreach(hash, cb, fdata);
}
static void
_eet_eina_hash_free(void *hash)
{
if (hash)
eina_hash_free(hash);
}
/*---*/
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;
}
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;
}
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;
}
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);
}
EAPI Eet_Data_Descriptor *
eet_data_descriptor2_new(const Eet_Data_Descriptor_Class *eddc)
{
return _eet_data_descriptor_new(eddc, 1);
}
EAPI Eet_Data_Descriptor *
eet_data_descriptor3_new(const Eet_Data_Descriptor_Class *eddc)
{
return _eet_data_descriptor_new(eddc, 2);
}
EAPI Eet_Data_Descriptor *
eet_data_descriptor_stream_new(const Eet_Data_Descriptor_Class *eddc)
{
return _eet_data_descriptor_new(eddc, 1);
}
EAPI Eet_Data_Descriptor *
eet_data_descriptor_file_new(const Eet_Data_Descriptor_Class *eddc)
{
return _eet_data_descriptor_new(eddc, 2);
}
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);
}
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;
EINA_SAFETY_ON_NULL_RETURN(edd);
/* Sanity check to avoid crash later at runtime */
if (type < EET_T_UNKNOW ||
type >= EET_T_LAST)
{
CRIT("Preventing later bug due to unknow type: %i", type);
return ;
}
if (offset < 0)
{
CRIT("Preventing later buffer underrun : offset = %i", offset);
return ;
}
if (offset > edd->size)
{
CRIT("Preventing later buffer overrun : offset = %i in a structure of %i bytes", offset, edd->size);
return ;
}
if (group_type == EET_G_UNKNOWN && type != EET_T_UNKNOW)
{
if (offset + eet_basic_codec[type - 1].size > edd->size)
{
CRIT("Preventing later buffer overrun : offset = %i, size = %i in a structure of %i bytes", offset, eet_basic_codec[type - 1].size, edd->size);
return ;
}
}
else if ((offset + sizeof (void*)) > (unsigned int) edd->size)
{
CRIT("Preventing later buffer overrun : offset = %i, estimated size = %zu in a structure of %i bytes", offset, sizeof (void*), edd->size);
return ;
}
/* 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;
}
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;
}
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;
}
EAPI void *
eet_data_read(Eet_File *ef,
Eet_Data_Descriptor *edd,
const char *name)
{
return eet_data_read_cipher(ef, edd, name, NULL);
}
EAPI int
eet_data_write_cipher(Eet_File *ef,
Eet_Data_Descriptor *edd,
const char *name,
const char *cipher_key,
const void *data,
int comp)
{
Eet_Dictionary *ed;
void *data_enc;
int size;
int val;
EINA_SAFETY_ON_NULL_RETURN_VAL(edd, 0);
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, comp, cipher_key);
free(data_enc);
return val;
}
EAPI int
eet_data_write(Eet_File *ef,
Eet_Data_Descriptor *edd,
const char *name,
const void *data,
int comp)
{
return eet_data_write_cipher(ef, edd, name, NULL, data, comp);
}
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;
}
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);
}
#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]);
}
static void
_eet_free_ref(Eet_Free *ef)
{
ef->ref++;
}
static void
_eet_free_unref(Eet_Free *ef)
{
ef->ref--;
}
#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);
}
#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);
}
#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);
}
#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);
}
#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);
}
#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);
}
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);
}
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);
}
static int
eet_data_descriptor_encode_hash_cb(void *hash EINA_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;
}
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;
}
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);
}
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-