forked from enlightenment/efl
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5026 lines
144 KiB
5026 lines
144 KiB
#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); |
|