From: Enlightenment S. <no-...@en...> - 2010-03-05 17:19:17
|
Log: * eet: Fix clearcache race condition. Patch by Adam Simpkins. Author: cedric Date: 2010-03-05 09:19:03 -0800 (Fri, 05 Mar 2010) New Revision: 46891 Modified: trunk/eet/AUTHORS trunk/eet/ChangeLog trunk/eet/src/lib/eet_lib.c trunk/eet/src/tests/eet_suite.c Modified: trunk/eet/AUTHORS =================================================================== --- trunk/eet/AUTHORS 2010-03-05 06:23:25 UTC (rev 46890) +++ trunk/eet/AUTHORS 2010-03-05 17:19:03 UTC (rev 46891) @@ -9,3 +9,4 @@ Raphael Kubo da Costa <ku...@pr...> Mathieu Taillefumier <mat...@fr...> Albin "Lutin" Tonnerre <alb...@gm...> +Adam Simpkins <ad...@ad...> Modified: trunk/eet/ChangeLog =================================================================== --- trunk/eet/ChangeLog 2010-03-05 06:23:25 UTC (rev 46890) +++ trunk/eet/ChangeLog 2010-03-05 17:19:03 UTC (rev 46891) @@ -337,3 +337,7 @@ 2010-03-01 Albin Tonnerre * Fix override of global symbols. + +2010-03-05 Adam Simpkins + + * Fix clearcache race condition. Modified: trunk/eet/src/lib/eet_lib.c =================================================================== --- trunk/eet/src/lib/eet_lib.c 2010-03-05 06:23:25 UTC (rev 46890) +++ trunk/eet/src/lib/eet_lib.c 2010-03-05 17:19:03 UTC (rev 46891) @@ -280,7 +280,7 @@ if (test) { ef->delete_me_now = 1; - eet_internal_close(ef, 0); + eet_internal_close(ef, 1); } return test; } @@ -307,6 +307,7 @@ } /* add to end of cache */ +/* this should only be called when the cache lock is already held */ static void eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc) { @@ -358,6 +359,7 @@ } /* delete from cache */ +/* this should only be called when the cache lock is already held */ static void eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc) { @@ -849,6 +851,7 @@ * We need to compute the list of eet file to close separately from the cache, * due to eet_close removing them from the cache after each call. */ + LOCK_CACHE; for (i = 0; i < eet_writers_num; i++) { if (eet_writers[i]->references <= 0) num++; @@ -887,9 +890,10 @@ for (i = 0; i < num; i++) { - eet_close(closelist[i]); + eet_internal_close(closelist[i], 1); } } + UNLOCK_CACHE; } /* FIXME: MMAP race condition in READ_WRITE_MODE */ @@ -1281,6 +1285,12 @@ } #endif +/* + * this should only be called when the cache lock is already held + * (We could drop this restriction if we add a parameter to eet_test_close + * that indicates if the lock is held or not. For now it is easiest + * to just require that it is always held.) + */ static Eet_File * eet_internal_read(Eet_File *ef) { @@ -1317,6 +1327,9 @@ /* check to see its' an eet file pointer */ if (eet_check_pointer(ef)) return EET_ERROR_BAD_OBJECT; + + if (!locked) LOCK_CACHE; + /* deref */ ef->references--; /* if its still referenced - dont go any further */ @@ -1329,17 +1342,18 @@ /* if not urgent to delete it - dont free it - leave it in cache */ if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ)) - return EET_ERROR_NONE; + { + if (!locked) UNLOCK_CACHE; + return EET_ERROR_NONE; + } /* remove from cache */ - if (!locked) - { - LOCK_CACHE; - } if (ef->mode == EET_FILE_MODE_READ) eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE)) eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); + + /* we can unlock the cache now */ if (!locked) { UNLOCK_CACHE; @@ -1425,7 +1439,11 @@ ef->sha1 = NULL; ef->sha1_length = 0; - return eet_internal_read(ef); + /* eet_internal_read expects the cache lock to be held when it is called */ + LOCK_CACHE; + ef = eet_internal_read(ef); + UNLOCK_CACHE; + return ef; } EAPI Eet_File * @@ -1466,7 +1484,6 @@ } ef = eet_cache_find((char *)file, eet_writers, eet_writers_num); } - UNLOCK_CACHE; /* try open the file based on mode */ if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE)) @@ -1475,23 +1492,23 @@ file_stat.st_mtime = 0; fp = fopen(file, "rb"); - if (!fp) goto on_error; + if (!fp) goto open_error; if (fstat(fileno(fp), &file_stat)) { fclose(fp); fp = NULL; - goto on_error; + goto open_error; } if ((mode == EET_FILE_MODE_READ) && (file_stat.st_size < ((int) sizeof(int) * 3))) { fclose(fp); fp = NULL; - goto on_error; + goto open_error; } - on_error: - if (fp == NULL && mode == EET_FILE_MODE_READ) return NULL; + open_error: + if (fp == NULL && mode == EET_FILE_MODE_READ) goto on_error; } else { @@ -1503,7 +1520,7 @@ unlink(file); fd = open(file, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); fp = fdopen(fd, "wb"); - if (!fp) return NULL; + if (!fp) goto on_error; } /* We found one */ @@ -1520,6 +1537,7 @@ /* reference it up and return it */ if (fp != NULL) fclose(fp); ef->references++; + UNLOCK_CACHE; return ef; } @@ -1528,7 +1546,7 @@ /* Allocate struct for eet file and have it zero'd out */ ef = malloc(sizeof(Eet_File) + file_len); if (!ef) - return NULL; + goto on_error; /* fill some of the members */ INIT_FILE(ef); @@ -1557,7 +1575,7 @@ /* if we can't open - bail out */ if (eet_test_close(!ef->fp, ef)) - return NULL; + goto on_error; fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC); /* if we opened for read or read-write */ @@ -1567,10 +1585,10 @@ ef->data = mmap(NULL, ef->data_size, PROT_READ, MAP_SHARED, fileno(ef->fp), 0); if (eet_test_close((ef->data == MAP_FAILED), ef)) - return NULL; + goto on_error; ef = eet_internal_read(ef); if (!ef) - return NULL; + goto on_error; } empty_file: @@ -1584,16 +1602,19 @@ /* add to cache */ if (ef->references == 1) { - LOCK_CACHE; if (ef->mode == EET_FILE_MODE_READ) eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE)) eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); - UNLOCK_CACHE; } + UNLOCK_CACHE; return ef; + +on_error: + UNLOCK_CACHE; + return NULL; } EAPI Eet_File_Mode Modified: trunk/eet/src/tests/eet_suite.c =================================================================== --- trunk/eet/src/tests/eet_suite.c 2010-03-05 06:23:25 UTC (rev 46890) +++ trunk/eet/src/tests/eet_suite.c 2010-03-05 17:19:03 UTC (rev 46891) @@ -6,6 +6,7 @@ #include <stdio.h> #include <fcntl.h> #include <unistd.h> +#include <pthread.h> #include <check.h> @@ -1410,7 +1411,66 @@ } END_TEST +static Eina_Bool open_worker_stop; +static void* +open_close_worker(void* path) +{ + while (!open_worker_stop) + { + Eet_File* ef = eet_open((char const*)path, EET_FILE_MODE_READ); + if (ef == NULL) + { + pthread_exit("eet_open() failed"); + } + else + { + Eet_Error err_code = eet_close(ef); + if (err_code != EET_ERROR_NONE) + pthread_exit("eet_close() failed"); + } + } + pthread_exit(NULL); +} + +START_TEST(eet_cache_concurrency) +{ + char *file = strdup("/tmp/eet_suite_testXXXXXX"); + const char *buffer = "test data"; + Eet_File *ef; + void *thread_ret; + unsigned int n; + + eet_init(); + + /* create a file to test with */ + fail_if(!mktemp(file)); + ef = eet_open(file, EET_FILE_MODE_WRITE); + fail_if(!ef); + fail_if(!eet_write(ef, "keys/tests", buffer, strlen(buffer) + 1, 0)); + + /* start a thread that repeatedly opens and closes a file */ + open_worker_stop = 0; + pthread_t thread; + pthread_create(&thread, NULL, open_close_worker, file); + + /* clear the cache repeatedly in this thread */ + for (n = 0; n < 100000; ++n) + { + eet_clearcache(); + } + + /* join the other thread, and fail if it returned an error message */ + open_worker_stop = 1; + fail_if(pthread_join(thread, &thread_ret) != 0); + fail_unless(thread_ret == NULL, (char const*)thread_ret); + + fail_if(unlink(file) != 0); + eet_shutdown(); +} +END_TEST + + Suite * eet_suite(void) { @@ -1455,6 +1515,10 @@ suite_add_tcase(s, tc); #endif + tc = tcase_create("Eet Cache"); + tcase_add_test(tc, eet_cache_concurrency); + suite_add_tcase(s, tc); + return s; } |
From: Enlightenment S. <no-...@en...> - 2010-04-02 13:51:07
|
Log: * eet: Add Eet_Connection. This will help people that want to use Eet over any kind of link. Author: cedric Date: 2010-04-02 06:51:00 -0700 (Fri, 02 Apr 2010) New Revision: 47688 Modified: trunk/eet/ChangeLog trunk/eet/src/lib/Eet.h trunk/eet/src/lib/Makefile.am trunk/eet/src/tests/eet_suite.c Modified: trunk/eet/ChangeLog =================================================================== --- trunk/eet/ChangeLog 2010-04-02 13:48:36 UTC (rev 47687) +++ trunk/eet/ChangeLog 2010-04-02 13:51:00 UTC (rev 47688) @@ -341,3 +341,8 @@ 2010-03-15 Adam Simpkins / Cedric BAIL * Fix clearcache race condition. + +2010-04-02 Cedric BAIL + + * Fix eet_data_node_read_cipher return type. + * Add Eet_Connection. Modified: trunk/eet/src/lib/Eet.h =================================================================== --- trunk/eet/src/lib/Eet.h 2010-04-02 13:48:36 UTC (rev 47687) +++ trunk/eet/src/lib/Eet.h 2010-04-02 13:51:00 UTC (rev 47688) @@ -2643,6 +2643,117 @@ EAPI void *eet_node_walk(void *parent, const char *name, Eet_Node *root, Eet_Node_Walk *cb, void *user_data); + /*******/ + + /** + * @defgroup Eet_Connection_Group Helper function to use eet over a network link + * + * Function that reconstruct and prepare packet of @ref Eet_Data_Group to be send. + * + */ + + /** + * @typedef Eet_Connection + * Opaque handle to track paquet for a specific connection. + * + * @ingroup Eet_Connection_Group + */ + typedef struct _Eet_Connection Eet_Connection; + + /** + * @typedef Eet_Read_Cb + * Called back when an @ref Eet_Data_Group has been received completly and could be used. + * + * @ingroup Eet_Connection_Group + */ + typedef Eina_Bool Eet_Read_Cb(const void *eet_data, size_t size, void *user_data); + + /** + * @typedef Eet_Write_Cb + * Called back when a packet containing @ref Eet_Data_Group data is ready to be send. + * + * @ingroup Eet_Connection_Group + */ + typedef Eina_Bool Eet_Write_Cb(const void *data, size_t size, void *user_data); + + /** + * Instanciate a new connection to track. + * @oaram eet_read_cb Function to call when one Eet_Data packet has been fully assemble. + * @param eet_write_cb Function to call when one Eet_Data packet is ready to be send over the wire. + * @param user_data Pointer provided to both functions to be used as a context handler. + * @return NULL on failure, or a valid Eet_Connection handler. + * + * For every connection to track you will need a separate Eet_Connection provider. + * + * @since 1.2.4 + * @ingroup Eet_Connection_Group + */ + Eet_Connection *eet_connection_new(Eet_Read_Cb *eet_read_cb, Eet_Write_Cb *eet_write_cb, const void *user_data); + + /** + * Process a raw packet received over the link + * @oaram conn Connection handler to track. + * @param data Raw data packet. + * @param size The size of that packet. + * @return 0 on complete success, any other value indicate where in the stream it got wrong (It could be before that packet). + * + * Every time you receive a packet related to your connection, you should pass + * it to that function so that it could process and assemble packet has you + * receive it. It will automatically call Eet_Read_Cb when one is fully received. + * + * @since 1.2.4 + * @ingroup Eet_Connection_Group + */ + int eet_connection_received(Eet_Connection *conn, const void *data, size_t size); + + /** + * Convert a complex structure and prepare it to be send. + * @oaram conn Connection handler to track. + * @param edd The data descriptor to use when encoding. + * @param data_in The pointer to the struct to encode into data. + * @param cipher_key The key to use as cipher. + * @return EINA_TRUE if the data where correctly send, EINA_FALSE if they don't. + * + * This function serialize data_in with edd, assemble the packet and call + * Eet_Write_Cb when ready. The data passed Eet_Write_Cb are temporary allocated + * and will vanish just after the return of the callback. + * + * @see eet_data_descriptor_encode_cipher + * + * @since 1.2.4 + * @ingroup Eet_Connection_Group + */ + Eina_Bool eet_connection_send(Eet_Connection *conn, Eet_Data_Descriptor *edd, const void *data_in, const char *cipher_key); + + /** + * Convert a Eet_Node tree and prepare it to be send. + * @oaram conn Connection handler to track. + * @param node The data tree to use when encoding. + * @param cipher_key The key to use as cipher. + * @return EINA_TRUE if the data where correctly send, EINA_FALSE if they don't. + * + * This function serialize node, assemble the packet and call + * Eet_Write_Cb when ready. The data passed Eet_Write_Cb are temporary allocated + * and will vanish just after the return of the callback. + * + * @see eet_data_node_encode_cipher + * + * @since 1.2.4 + * @ingroup Eet_Connection_Group + */ + Eina_Bool eet_connection_node_send(Eet_Connection *conn, Eet_Node *node, const char *cipher_key); + + /** + * Close a connection and lost its track. + * @oaram conn Connection handler to close. + * @param on_going Signal if a partial packet wasn't completed. + * @return the user_data passed to both callback. + * + * @since 1.2.4 + * @ingroup Eet_Connection_Group + */ + void *eet_connection_close(Eet_Connection *conn, Eina_Bool *on_going); + /***************************************************************************/ #ifdef __cplusplus Modified: trunk/eet/src/lib/Makefile.am =================================================================== --- trunk/eet/src/lib/Makefile.am 2010-04-02 13:48:36 UTC (rev 47687) +++ trunk/eet/src/lib/Makefile.am 2010-04-02 13:51:00 UTC (rev 47688) @@ -27,7 +27,8 @@ eet_cipher.c \ eet_dictionary.c \ eet_node.c \ -eet_utils.c +eet_utils.c \ +eet_connection.c if EET_AMALGAMATION nodist_libeet_la_SOURCES = eet_amalgamation.c Modified: trunk/eet/src/tests/eet_suite.c =================================================================== --- trunk/eet/src/tests/eet_suite.c 2010-04-02 13:48:36 UTC (rev 47687) +++ trunk/eet/src/tests/eet_suite.c 2010-04-02 13:51:00 UTC (rev 47688) @@ -1470,7 +1470,131 @@ } END_TEST +typedef struct _Eet_Connection_Data Eet_Connection_Data; +struct _Eet_Connection_Data +{ + Eet_Connection *conn; + Eet_Data_Descriptor *edd; + Eina_Bool test; +}; +static Eina_Bool +_eet_connection_read(const void *eet_data, size_t size, void *user_data) +{ + Eet_Connection_Data *dt = user_data; + Eet_Test_Ex_Type *result; + Eet_Node *node; + int test; + + result = eet_data_descriptor_decode(dt->edd, eet_data, size); + node = eet_data_node_decode_cipher(eet_data, NULL, size); + + /* Test the resulting data. */ + fail_if(!node); + fail_if(_eet_test_ex_check(result, 0) != 0); + fail_if(_eet_test_ex_check(eina_list_data_get(result->list), 1) != 0); + fail_if(eina_list_data_get(result->ilist) == NULL); + fail_if(*((int*)eina_list_data_get(result->ilist)) != 42); + fail_if(eina_list_data_get(result->slist) == NULL); + fail_if(strcmp(eina_list_data_get(result->slist), "test") != 0); + fail_if(eina_hash_find(result->shash, EET_TEST_KEY1) == NULL); + fail_if(strcmp(eina_hash_find(result->shash, EET_TEST_KEY1), "test") != 0); + fail_if(strcmp(result->charray[0], "test") != 0); + + test = 0; + if (result->hash) eina_hash_foreach(result->hash, func, &test); + fail_if(test != 0); + if (result->ihash) eina_hash_foreach(result->ihash, func7, &test); + fail_if(test != 0); + + if (!dt->test) + { + dt->test = EINA_TRUE; + fail_if(!eet_connection_node_send(dt->conn, node, NULL)); + } + + return EINA_TRUE; +} + +static Eina_Bool +_eet_connection_write(const void *data, size_t size, void *user_data) +{ + Eet_Connection_Data *dt = user_data; + int still; + + if (!dt->test) + { + int step = size / 3; + + eet_connection_received(dt->conn, data, step); + eet_connection_received(dt->conn, (char*) data + step, step); + size -= 2 * step; + still = eet_connection_received(dt->conn, (char*) data + 2 * step, size); + } + else + still = eet_connection_received(dt->conn, data, size); + fail_if(still); + + return EINA_TRUE; +} + +START_TEST(eet_connection_check) +{ + Eet_Connection *conn; + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor_Class eddc; + Eet_Connection_Data ecd; + Eet_Test_Ex_Type etbt; + Eina_Bool on_going; + + eet_init(); + + _eet_test_ex_set(&etbt, 0); + etbt.list = eina_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.list = eina_list_prepend(etbt.list, _eet_test_ex_set(NULL, 1)); + etbt.hash = eina_hash_string_superfast_new(NULL); + eina_hash_add(etbt.hash, EET_TEST_KEY1, _eet_test_ex_set(NULL, 2)); + eina_hash_add(etbt.hash, EET_TEST_KEY2, _eet_test_ex_set(NULL, 2)); + etbt.ilist = eina_list_prepend(etbt.ilist, &i42); + etbt.ilist = eina_list_prepend(etbt.ilist, &i42); + etbt.ihash = eina_hash_string_superfast_new(NULL); + eina_hash_add(etbt.ihash, EET_TEST_KEY1, &i7); + eina_hash_add(etbt.ihash, EET_TEST_KEY2, &i7); + etbt.slist = eina_list_prepend(NULL, "test"); + etbt.shash = eina_hash_string_superfast_new(NULL); + eina_hash_add(etbt.shash, EET_TEST_KEY1, "test"); + memset(&etbt.charray, 0, sizeof(etbt.charray)); + etbt.charray[0] = "test"; + + eet_eina_file_data_descriptor_class_set(&eddc, "Eet_Test_Ex_Type", sizeof(Eet_Test_Ex_Type)); + + edd = eet_data_descriptor_file_new(&eddc); + fail_if(!edd); + + _eet_build_ex_descriptor(edd); + + /* Create a connection. */ + conn = eet_connection_new(_eet_connection_read, _eet_connection_write, &ecd); + fail_if(!conn); + + /* Init context. */ + ecd.test = EINA_FALSE; + ecd.conn = conn; + ecd.edd = edd; + + /* Test the connection. */ + fail_if(!eet_connection_send(conn, edd, &etbt, NULL)); + + fail_if(!ecd.test); + + fail_if(!eet_connection_close(conn, &on_going)); + + fail_if(on_going); + + eet_shutdown(); +} +END_TEST + Suite * eet_suite(void) { @@ -1519,6 +1643,10 @@ tcase_add_test(tc, eet_cache_concurrency); suite_add_tcase(s, tc); + tc = tcase_create("Eet Connection"); + tcase_add_test(tc, eet_connection_check); + suite_add_tcase(s, tc); + return s; } |
From: Enlightenment S. <no-...@en...> - 2010-04-21 14:00:32
|
Log: * eet: Add EET_G_VARIANT and EET_G_UNION. This are the basis for a new edje file format. Next to come EET_G_INHERIT. Author: cedric Date: 2010-04-21 07:00:24 -0700 (Wed, 21 Apr 2010) New Revision: 48201 Modified: trunk/eet/ChangeLog trunk/eet/src/lib/Eet.h trunk/eet/src/lib/eet_data.c trunk/eet/src/lib/eet_dictionary.c trunk/eet/src/tests/eet_suite.c Modified: trunk/eet/ChangeLog =================================================================== --- trunk/eet/ChangeLog 2010-04-21 13:47:42 UTC (rev 48200) +++ trunk/eet/ChangeLog 2010-04-21 14:00:24 UTC (rev 48201) @@ -365,3 +365,7 @@ 2010-04-16 Cedric BAIL * Handle fixed point in data stream. + +2010-04-21 Cedric BAIL + + * Add EET_G_UNION and EET_G_VARIANT. Modified: trunk/eet/src/lib/Eet.h =================================================================== --- trunk/eet/src/lib/Eet.h 2010-04-21 13:47:42 UTC (rev 48200) +++ trunk/eet/src/lib/Eet.h 2010-04-21 14:00:24 UTC (rev 48201) @@ -274,7 +274,7 @@ * * If the eet file handle is not valid nothing will be done. * - * @since 1.2.3 + * @since 1.2.4 * @ingroup Eet_File_Group */ EAPI Eet_Error eet_sync(Eet_File *ef); @@ -1491,7 +1491,10 @@ #define EET_G_VAR_ARRAY 102 /**< Variable size array group type */ #define EET_G_LIST 103 /**< Linked list group type */ #define EET_G_HASH 104 /**< Hash table group type */ -#define EET_G_LAST 105 /**< Last group type */ +#define EET_G_UNION 105 /**< Union group type */ +#define EET_G_INHERIT 106 /**< Inherit object group type */ +#define EET_G_VARIANT 107 /**< Selectable subtype group */ +#define EET_G_LAST 108 /**< Last group type */ #define EET_I_LIMIT 128 /**< Other type exist but are reserved for internal purpose. */ @@ -1518,7 +1521,7 @@ * version member so it is compatible with abi changes, or at least * will not crash with them. */ -#define EET_DATA_DESCRIPTOR_CLASS_VERSION 2 +#define EET_DATA_DESCRIPTOR_CLASS_VERSION 3 /** * @typedef Eet_Data_Descriptor_Class @@ -1557,6 +1560,9 @@ void (*hash_free) (void *h); /**< free all entries from the hash @p h */ char *(*str_direct_alloc) (const char *str); /**< how to allocate a string directly from file backed/mmaped region pointed by @p str */ void (*str_direct_free) (const char *str); /**< how to free a string returned by str_direct_alloc */ + + const char *(*type_get) (const void *data, Eina_Bool *unknow); /**< convert any kind of data type to a name that define an Eet_Data_Element. */ + Eina_Bool (*type_set) (const char *type, void *data, Eina_Bool unknow); /**< set the type at a particular adress */ } func; }; @@ -2164,6 +2170,109 @@ } /** + * Add an union type to a data descriptor + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member + * (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param type_member The member that give hints on what is in the union. + * @param unified_type Describe all possible type the union could handle. + * + * This macro lets you easily add an union with a member that specify what is inside. + * The @p unified_type is an Eet_Data_Descriptor, but only the entry that match the name + * returned by type_get will be used for each serialized data. The type_get and type_set + * callback of unified_type should be defined. + * + * @since 1.2.4 + * @ingroup Eet_Data_Group + * @see Eet_Data_Descriptor_Class + */ +#define EET_DATA_DESCRIPTOR_ADD_UNION(edd, struct_type, name, member, type_member, unified_type) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_UNION, \ + (char *) (&(___ett.member)) - (char *)(&(___ett)), \ + (char *) (&(___ett.type_member)) - (char *)(&(___ett)), \ + NULL, unified_type); \ + } + + /** + * Make a structure variable in size/content depend on it's type + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member + * (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param type_member The member that give hints on what is in the union. + * @param unified_type Describe all possible type the union could handle. + * + * This macro lets you easily add a switch for an object oriented representation. The position + * of the member that define the type must be fixed for all possible type. Eet will then choose + * in the unified_type the structure that need to be allocated to match the detected type. + * The type_get and type_set callback of unified_type should be defined. This should be the only + * type in edd. + * + * @since 1.2.4 + * @ingroup Eet_Data_Group + * @see Eet_Data_Descriptor_Class + */ +#define EET_DATA_DESCRIPTOR_ADD_INHERIT(edd, struct_type, name, member, type_member, unified_type) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_INHERIT, \ + (char *) (&(___ett.member)) - (char *)(&(___ett)), \ + (char *) (&(___ett.type_member)) - (char *)(&(___ett)), \ + NULL, unified_type); \ + } + + /** + * Add a automatically selectable type to a data descriptor + * @param edd The data descriptor to add the type to. + * @param struct_type The type of the struct. + * @param name The string name to use to encode/decode this member + * (must be a constant global and never change). + * @param member The struct member itself to be encoded. + * @param type_member The member that give hints on what is in the union. + * @param unified_type Describe all possible type the union could handle. + * + * This macro lets you easily define what the content of @p member points to depending of + * the content of @p type_member. The type_get and type_set callback of unified_type should + * be defined. If the the type is not know at the time of restoring it, eet will still call + * type_set of @p unified_type but the pointer will be set to a serialized binary representation + * of what eet know. This make it possible, to save this pointer again by just returning the string + * given previously and telling it by setting unknow to EINA_TRUE. + * + * @since 1.2.4 + * @ingroup Eet_Data_Group + * @see Eet_Data_Descriptor_Class + */ +#define EET_DATA_DESCRIPTOR_ADD_VARIANT(edd, struct_type, name, member, type_member, unified_type) \ + { \ + struct_type ___ett; \ + \ + eet_data_descriptor_element_add(edd, name, EET_T_UNKNOW, EET_G_VARIANT, \ + (char *) (&(___ett.member)) - (char *)(&(___ett)), \ + (char *) (&(___ett.type_member)) - (char *)(&(___ett)), \ + NULL, unified_type); \ + } + + /** + * Add a mapping to a data descriptor that will be used by union, variant or inherited type + * @param unified_type The data descriptor to add the mapping to. + * @param name The string name to get/set type. + * @param subtype The matching data descriptor. + * + * @since 1.2.4 + * @ingroup Eet_Data_Group + * @see Eet_Data_Descriptor_Class + */ +#define EET_DATA_DESCRIPTOR_ADD_MAPPING(unified_type, name, subtype) \ + eet_data_descriptor_element_add(unified_type, name, EET_T_UNKNOW, EET_G_UNKNOWN, 0, 0, NULL, subtype); + + /** * @defgroup Eet_Data_Cipher_Group Eet Data Serialization using A Ciphers * * Most of the @ref Eet_Data_Group have alternative versions that Modified: trunk/eet/src/lib/eet_data.c =================================================================== --- trunk/eet/src/lib/eet_data.c 2010-04-21 13:47:42 UTC (rev 48200) +++ trunk/eet/src/lib/eet_data.c 2010-04-21 14:00:24 UTC (rev 48201) @@ -74,6 +74,7 @@ typedef struct _Eet_Data_Encode_Hash_Info Eet_Data_Encode_Hash_Info; typedef struct _Eet_Free Eet_Free; typedef struct _Eet_Free_Context Eet_Free_Context; +typedef struct _Eet_Variant_Unknow Eet_Variant_Unknow; /*---*/ @@ -138,6 +139,8 @@ void (*hash_foreach) (void *h, int (*func) (void *h, const char *k, void *dt, void *fdt), void *fdt); void *(*hash_add) (void *h, const char *k, void *d); void (*hash_free) (void *h); + const char *(*type_get) (const void *data, Eina_Bool *unknow); + Eina_Bool (*type_set) (const char *type, void *data, Eina_Bool unknow); } func; struct { int num; @@ -147,6 +150,8 @@ Eet_Data_Descriptor_Hash *buckets; } hash; } elements; + + Eina_Bool unified_type : 1; // char *strings; // int strings_len; }; @@ -188,6 +193,14 @@ Eet_Free freelist_direct_str; }; +struct _Eet_Variant_Unknow +{ + EINA_MAGIC; + + int size; + char data[1]; +}; + /*---*/ static int eet_data_get_char(const Eet_Dictionary *ed, const void *src, const void *src_end, void *dest); @@ -228,6 +241,12 @@ static void eet_data_put_list(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); static void eet_data_put_hash(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); static int eet_data_get_hash(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, char **p, int *size); +static void eet_data_put_union(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); +static int eet_data_get_union(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, char **p, int *size); +static void eet_data_put_inherit(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); +static int eet_data_get_inherit(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, char **p, int *size); +static void eet_data_put_variant(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in); +static int eet_data_get_variant(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, Eet_Data_Chunk *echnk, int type, int group_type, void *data, char **p, int *size); static void eet_data_chunk_get(const Eet_Dictionary *ed, Eet_Data_Chunk *chnk, const void *src, int size); static Eet_Data_Chunk *eet_data_chunk_new(void *data, int size, const char *name, int type, int group_type); @@ -275,7 +294,10 @@ { eet_data_get_array, eet_data_put_array }, { eet_data_get_array, eet_data_put_array }, { eet_data_get_list, eet_data_put_list }, - { eet_data_get_hash, eet_data_put_hash } + { eet_data_get_hash, eet_data_put_hash }, + { eet_data_get_union, eet_data_put_union }, + { eet_data_get_inherit, eet_data_put_inherit }, + { eet_data_get_variant, eet_data_put_variant } }; static int _eet_data_words_bigendian = -1; @@ -325,6 +347,7 @@ #define EET_I_INLINED_STRING 2 << 4 #define EET_I_NULL 3 << 4 +#define EET_MAGIC_VARIANT 0xF1234BC /*---*/ /* CHAR TYPE */ @@ -1305,7 +1328,6 @@ Eet_Data_Descriptor *edd; if (!eddc) return NULL; - if (eddc->version < version) return NULL; edd = calloc(1, sizeof (Eet_Data_Descriptor)); if (!edd) return NULL; @@ -1333,11 +1355,16 @@ edd->func.hash_add = eddc->func.hash_add; edd->func.hash_free = eddc->func.hash_free; - if (version > 1) + if (eddc->version > 1 && version > 1) { edd->func.str_direct_alloc = eddc->func.str_direct_alloc; edd->func.str_direct_free = eddc->func.str_direct_free; } + if (eddc->version > 2) + { + edd->func.type_get = eddc->func.type_get; + edd->func.type_set = eddc->func.type_set; + } return edd; } @@ -1421,6 +1448,43 @@ Eet_Data_Element *ede; Eet_Data_Element *tmp; + /* UNION, INHERITED or VARIANT type would not work with simple type, we need a way to map the type. */ + if ((group_type == EET_G_INHERIT + || group_type == EET_G_UNION + || group_type == EET_G_VARIANT) + && + (type != EET_T_UNKNOW + || subtype == NULL + || subtype->func.type_get == NULL + || subtype->func.type_set == NULL)) + return ; + + /* Only one element is allowed with INHERITED type */ + if (group_type == EET_G_INHERIT && edd->elements.num != 0) + return ; + if (edd->elements.num > 0 && edd->elements.set[0].group_type == EET_G_INHERIT) + return ; + + /* VARIANT type will only work if the map only contains EET_G_*, but not INHERIT, UNION, VARIANT and ARRAY. */ + if (group_type == EET_G_VARIANT) + { + int i; + + for (i = 0; i < subtype->elements.num; ++i) + if (subtype->elements.set[i].type != EET_T_UNKNOW + && subtype->elements.set[i].group_type > EET_G_VAR_ARRAY + && subtype->elements.set[i].group_type < EET_G_UNION) + return ; + + subtype->unified_type = EINA_TRUE; + } + if (subtype + && subtype->unified_type + && (type != EET_T_UNKNOW + || group_type < EET_G_UNION)) + return ; + + /* Sanity check done, let allocate ! */ edd->elements.num++; tmp = realloc(edd->elements.set, edd->elements.num * sizeof(Eet_Data_Element)); if (!tmp) return ; @@ -1455,7 +1519,7 @@ ede->group_type = group_type; ede->offset = offset; ede->count = count; - /* FIXME: For the time being, EET_G_VAR_ARRAY will put the counter_offset in count. */ + /* FIXME: For the time being, VAR_ARRAY, INHERIT, UNION and VARIANT will put the counter_offset in count. */ ede->counter_offset = count; /* ede->counter_offset = counter_offset; */ ede->counter_name = counter_name; @@ -2440,12 +2504,14 @@ break; case EET_G_VAR_ARRAY: return eet_node_var_array_new(chnk.name, NULL); + case EET_G_INHERIT: + /* This one should work */ + goto error; case EET_G_LIST: - goto error; case EET_G_HASH: - goto error; case EET_G_ARRAY: - goto error; + case EET_G_UNION: + case EET_G_VARIANT: default: goto error; } @@ -2818,6 +2884,379 @@ return 0; } +static void +eet_data_put_union(Eet_Dictionary *ed, + __UNUSED__ Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in) +{ + const char *union_type; + int i; + + EET_ASSERT(!((ede->type != EET_T_UNKNOW) || (!ede->subtype)), return ); + + union_type = ede->subtype->func.type_get(((char*) data_in) + ede->count - ede->offset, + NULL); + + if (!union_type) return ; + + /* Search the structure of the union to encode. */ + for (i = 0; i < ede->subtype->elements.num; ++i) + if (strcmp(ede->subtype->elements.set[i].name, union_type) == 0) + { + Eet_Data_Element *sede; + void *data; + int size; + + /* Yeah we found it ! */ + data = eet_data_put_type(ed, EET_T_STRING, &union_type, &size); + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + + sede = &(ede->subtype->elements.set[i]); + data = _eet_data_descriptor_encode(ed, + sede->subtype, + data_in, + &size); + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + break; + } +} + +static int +eet_data_get_union(Eet_Free_Context *context, const Eet_Dictionary *ed, + __UNUSED__ Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, Eet_Data_Chunk *echnk, + int type, int group_type, void *data, + char **p, int *size) +{ + const char *union_type; + void *data_ret = NULL; + int ret = 0; + int i; + + /* Read type */ + ret = eet_data_get_type(ed, + EET_T_STRING, + echnk->data, + ((char *)echnk->data) + echnk->size, + &union_type); + if (ret <= 0) goto on_error; + + /* Advance to next chunk */ + NEXT_CHUNK((*p), (*size), (*echnk), ed); + memset(echnk, 0, sizeof(Eet_Data_Chunk)); + + /* Read value */ + eet_data_chunk_get(ed, echnk, *p, *size); + if (!echnk->name) goto on_error; + + if (ede) + { + EET_ASSERT(!(ede->group_type != group_type || ede->type != type), goto on_error); + + /* Search the structure of the union to decode */ + for (i = 0; i < ede->subtype->elements.num; ++i) + if (strcmp(ede->subtype->elements.set[i].name, union_type) == 0) + { + Eet_Data_Element *sede; + + /* Yeah we found it ! */ + sede = &(ede->subtype->elements.set[i]); + EET_ASSERT(sede->subtype, goto on_error); + + data_ret = _eet_data_descriptor_decode(context, + ed, + sede->subtype, + echnk->data, + echnk->size); + if (!data_ret) goto on_error; + + /* Memcopy the structure content to remove pointer indirection. */ + memcpy(data, data_ret, sede->subtype->size); + + /* data_ret is now useless. */ + sede->subtype->func.mem_free(data_ret); + + /* Set union type. */ + if ((!ed) || (!ede->subtype->func.str_direct_alloc)) + { + union_type = ede->subtype->func.str_alloc(union_type); + _eet_freelist_str_add(context, (char*) union_type); + } + else + { + union_type = ede->subtype->func.str_direct_alloc(union_type); + _eet_freelist_direct_str_add(context, (char*) union_type); + } + + ede->subtype->func.type_set(union_type, + ((char*) data) + ede->count - ede->offset, + EINA_FALSE); + + break; + } + } + else + { + /* FIXME: generate node structure. */ + data_ret = _eet_data_descriptor_decode(context, + ed, NULL, + echnk->data, echnk->size); + goto on_error; + } + + return 1; + + on_error: + return 0; +} + +static void +eet_data_put_inherit(Eet_Dictionary *ed, Eet_Data_Descriptor *edd, Eet_Data_Element *ede, + Eet_Data_Stream *ds, void *data_in) +{ + /* FIXME */ + fprintf(stderr, "wrong !!!\n"); +} + +static int +eet_data_get_inherit(Eet_Free_Context *context, const Eet_Dictionary *ed, Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, Eet_Data_Chunk *echnk, + int type, int group_type, void *data, + char **p, int *size) +{ + /* FIXME */ + return 0; +} + +static void +eet_data_put_variant(Eet_Dictionary *ed, + __UNUSED__ Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, Eet_Data_Stream *ds, void *data_in) +{ + const char *union_type; + void *data; + Eina_Bool unknow = EINA_FALSE; + int size; + int i; + + EET_ASSERT(!((ede->type != EET_T_UNKNOW) || (!ede->subtype)), return ); + + union_type = ede->subtype->func.type_get(((char*) data_in) + ede->count - ede->offset, + &unknow); + + if (!union_type && unknow == EINA_FALSE) return ; + + if (unknow) + { + /* Handle opaque internal representation */ + Eet_Variant_Unknow *evu; + + data = eet_data_put_type(ed, EET_T_STRING, &union_type, &size); + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + + evu = (Eet_Variant_Unknow*) data_in; + if (evu && EINA_MAGIC_CHECK(evu, EET_MAGIC_VARIANT)) + eet_data_encode(ed, ds, evu->data, ede->name, evu->size, ede->type, ede->group_type); + } + else + { + /* Search the structure of the union to encode. */ + for (i = 0; i < ede->subtype->elements.num; ++i) + if (strcmp(ede->subtype->elements.set[i].name, union_type) == 0) + { + Eet_Data_Element *sede; + + /* Yeah we found it ! */ + data = eet_data_put_type(ed, EET_T_STRING, &union_type, &size); + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + + sede = &(ede->subtype->elements.set[i]); + + if (sede->group_type != EET_G_UNKNOWN) + { + Eet_Data_Stream *lds; + + lds = eet_data_stream_new(); + eet_group_codec[sede->group_type - 100].put(ed, + sede->subtype, + sede, + lds, + data_in); + if (lds->size != 0) + { + eet_data_encode(ed, ds, lds->data, ede->name, lds->pos, + ede->type, ede->group_type); + + lds->data = NULL; + lds->size = 0; + } + else + { + eet_data_encode(ed, ds, NULL, ede->name, 0, + EET_T_NULL, ede->group_type); + } + + eet_data_stream_free(lds); + } + else + { + data = _eet_data_descriptor_encode(ed, + sede->subtype, + *(void**)data_in, + &size); + if (data) eet_data_encode(ed, ds, data, ede->name, size, ede->type, ede->group_type); + } + + break; + } + } +} + +static int +eet_data_get_variant(Eet_Free_Context *context, const Eet_Dictionary *ed, + __UNUSED__ Eet_Data_Descriptor *edd, + Eet_Data_Element *ede, Eet_Data_Chunk *echnk, + int type, int group_type, void *data, + char **p, int *size) +{ + const char *union_type; + void *data_ret = NULL; + int ret = 0; + int i; + + /* Read type */ + ret = eet_data_get_type(ed, + EET_T_STRING, + echnk->data, + ((char *)echnk->data) + echnk->size, + &union_type); + if (ret <= 0) goto on_error; + + /* Advance to next chunk */ + NEXT_CHUNK((*p), (*size), (*echnk), ed); + memset(echnk, 0, sizeof(Eet_Data_Chunk)); + + /* Read value */ + eet_data_chunk_get(ed, echnk, *p, *size); + if (!echnk->name) goto on_error; + + if (ede) + { + EET_ASSERT(ede->subtype, goto on_error); + + if ((!ed) || (!ede->subtype->func.str_direct_alloc)) + { + union_type = ede->subtype->func.str_alloc(union_type); + _eet_freelist_str_add(context, (char*) union_type); + } + else + { + union_type = ede->subtype->func.str_direct_alloc(union_type); + _eet_freelist_direct_str_add(context, (char*) union_type); + } + + /* Search the structure of the union to decode */ + for (i = 0; i < ede->subtype->elements.num; ++i) + if (strcmp(ede->subtype->elements.set[i].name, union_type) == 0) + { + Eet_Data_Element *sede; + + /* Yeah we found it ! */ + sede = &(ede->subtype->elements.set[i]); + + if (sede->group_type != EET_G_UNKNOWN) + { + Eet_Data_Chunk chnk; + char *p2; + int size2; + int ret; + + p2 = echnk->data; + size2 = echnk->size; + + /* Didn't find a proper way to provide this + without duplicating code */ + while (size2 > 0) + { + memset(&chnk, 0, sizeof(Eet_Data_Chunk)); + eet_data_chunk_get(ed, &chnk, p2, size2); + + if (!chnk.name) goto on_error; + + ret = eet_group_codec[sede->group_type - 100].get(context, + ed, sede->subtype, + sede, &chnk, + sede->type, sede->group_type, + data, &p2, &size2); + + if (ret <= 0) goto on_error; + + /* advance to next chunk */ + NEXT_CHUNK(p2, size2, chnk, ed); + } + + /* Put garbage so that we will not put eet_variant_unknow in it */ + data_ret = (void*) data; + + /* Set variant type. */ + ede->subtype->func.type_set(union_type, + ((char*) data) + ede->count - ede->offset, + EINA_FALSE); + break; + } + + data_ret = _eet_data_descriptor_decode(context, + ed, + sede->subtype, + echnk->data, + echnk->size); + if (!data_ret) break; + + /* And point to the variant data. */ + *(void**) data = data_ret; + + /* Set variant type. */ + ede->subtype->func.type_set(union_type, + ((char*) data) + ede->count - ede->offset, + EINA_FALSE); + break; + } + + if (!data_ret) + { + Eet_Variant_Unknow *evu; + + evu = calloc(1, sizeof (Eet_Variant_Unknow) + echnk->size - 1); + if (!evu) goto on_error; + + evu->size = echnk->size; + memcpy(evu->data, echnk->data, evu->size); + EINA_MAGIC_SET(evu, EET_MAGIC_VARIANT); + + /* And point to the opaque internal data scructure */ + *(void**) data = evu; + + /* Set variant type. */ + ede->subtype->func.type_set(union_type, + ((char*) data) + ede->count - ede->offset, + EINA_TRUE); + } + } + else + { + /* FIXME: dump node structure. */ + data_ret = _eet_data_descriptor_decode(context, + ed, NULL, + echnk->data, echnk->size); + goto on_error; + } + + return 1; + + on_error: + return 0; +} + static Eet_Node * eet_data_node_simple_type(int type, const char *name, void *dd) { Modified: trunk/eet/src/lib/eet_dictionary.c =================================================================== --- trunk/eet/src/lib/eet_dictionary.c 2010-04-21 13:47:42 UTC (rev 48200) +++ trunk/eet/src/lib/eet_dictionary.c 2010-04-21 14:00:24 UTC (rev 48201) @@ -325,7 +325,7 @@ str = ed->all[idx].str ? ed->all[idx].str : ed->all[idx].mmap; - if (!eina_convert_atofp(str, ed->all[idx].len, &fp)) + if (!eina_convert_atofp(str, ed->all[idx].len, &fp)) return EINA_FALSE; ed->all[idx].fp = fp; Modified: trunk/eet/src/tests/eet_suite.c =================================================================== --- trunk/eet/src/tests/eet_suite.c 2010-04-21 13:47:42 UTC (rev 48200) +++ trunk/eet/src/tests/eet_suite.c 2010-04-21 14:00:24 UTC (rev 48201) @@ -1756,6 +1756,430 @@ } END_TEST +typedef struct _Eet_Union_Test Eet_Union_Test; +typedef struct _Eet_Variant_Test Eet_Variant_Test; +typedef struct _Eet_Variant_Type Eet_Variant_Type; +typedef struct _Eet_Inherit_Test1 Eet_Inherit_Test1; +typedef struct _Eet_Inherit_Test2 Eet_Inherit_Test2; +typedef struct _Eet_Inherit_Test3 Eet_Inherit_Test3; +typedef struct _Eet_St1 Eet_St1; +typedef struct _Eet_St2 Eet_St2; +typedef struct _Eet_St3 Eet_St3; +typedef struct _Eet_List Eet_List; + +typedef enum _Eet_Union +{ + EET_UNKNOWN, + EET_ST1, + EET_ST2, + EET_ST3 +} Eet_Union; + +struct { + Eet_Union u; + const char *name; +} eet_mapping[] = { + { EET_ST1, "ST1" }, + { EET_ST2, "ST2" }, + { EET_ST3, "ST3" }, + { EET_UNKNOWN, NULL } +}; + +struct _Eet_St1 +{ + double val1; + int stuff; + char *s1; +}; + +struct _Eet_St2 +{ + Eina_Bool b1; + unsigned long long v1; +}; + +struct _Eet_St3 +{ + int boby; +}; + +struct _Eet_Union_Test +{ + Eet_Union type; + + union { + Eet_St1 st1; + Eet_St2 st2; + Eet_St3 st3; + } u; +}; + +struct _Eet_Variant_Type +{ + const char *type; + Eina_Bool unknow : 1; +}; + +struct _Eet_Variant_Test +{ + Eet_Variant_Type t; + + void *data; + Eina_List *data_list; +}; + +struct _Eet_Inherit_Test1 +{ + Eet_Union type; + Eet_St1 st1; +}; +struct _Eet_Inherit_Test2 +{ + Eet_Union type; + Eet_St2 st2; +}; +struct _Eet_Inherit_Test3 +{ + Eet_Union type; + Eet_St3 st3; +}; + +struct _Eet_List +{ + Eina_List *list; +}; + +static const char * +_eet_union_type_get(const void *data, Eina_Bool *unknow) +{ + const Eet_Union *u = data; + int i; + + if (unknow) *unknow = EINA_FALSE; + for (i = 0; eet_mapping[i].name != NULL; ++i) + if (*u == eet_mapping[i].u) + return eet_mapping[i].name; + + if (unknow) *unknow = EINA_TRUE; + return NULL; +} + +static Eina_Bool +_eet_union_type_set(const char *type, void *data, Eina_Bool unknow) +{ + Eet_Union *u = data; + int i; + + if (unknow) return EINA_FALSE; + + for (i = 0; eet_mapping[i].name != NULL; ++i) + if (strcmp(eet_mapping[i].name, type) == 0) + { + *u = eet_mapping[i].u; + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static const char * +_eet_variant_type_get(const void *data, Eina_Bool *unknow) +{ + const Eet_Variant_Type *type = data; + int i; + + if (unknow) *unknow = type->unknow; + for (i = 0; eet_mapping[i].name != NULL; ++i) + if (strcmp(type->type, eet_mapping[i].name) == 0) + return eet_mapping[i].name; + + if (unknow) *unknow = EINA_FALSE; + return type->type; +} + +static Eina_Bool +_eet_variant_type_set(const char *type, void *data, Eina_Bool unknow) +{ + Eet_Variant_Type *vt = data; + + vt->type = type; + vt->unknow = unknow; + return EINA_TRUE; +} + +static Eet_Data_Descriptor* +_eet_st1_dd(void) +{ + Eet_Data_Descriptor_Class eddc; + Eet_Data_Descriptor *res; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_St1); + res = eet_data_descriptor_stream_new(&eddc); + EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St1, "val1", val1, EET_T_DOUBLE); + EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St1, "stuff", stuff, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St1, "s1", s1, EET_T_STRING); + + return res; +} + +static void +_eet_st1_set(Eet_St1 *st1, int i) +{ + st1->val1 = EET_TEST_DOUBLE; + st1->stuff = EET_TEST_INT + i; + st1->s1 = EET_TEST_STRING; +} + +static void +_eet_st1_cmp(Eet_St1 *st1, int i) +{ + double tmp; + + fail_if(!st1); + + tmp = st1->val1 - EET_TEST_DOUBLE; + if (tmp < 0) tmp = -tmp; + fail_if(tmp > 0.005); + fail_if(st1->stuff != EET_TEST_INT + i); + fail_if(strcmp(st1->s1, EET_TEST_STRING)); +} + +static Eet_Data_Descriptor* +_eet_st2_dd(void) +{ + Eet_Data_Descriptor_Class eddc; + Eet_Data_Descriptor *res; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_St2); + res = eet_data_descriptor_stream_new(&eddc); + EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St2, "b1", b1, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St2, "v1", v1, EET_T_ULONG_LONG); + + return res; +} + +static void +_eet_st2_set(Eet_St2 *st2, int i) +{ + st2->b1 = EINA_TRUE; + st2->v1 = EET_TEST_LONG_LONG + i; +} + +static void +_eet_st2_cmp(Eet_St2 *st2, int i) +{ + fail_if(!st2->b1); + fail_if(st2->v1 != EET_TEST_LONG_LONG + i); +} + +static Eet_Data_Descriptor* +_eet_st3_dd(void) +{ + Eet_Data_Descriptor_Class eddc; + Eet_Data_Descriptor *res; + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_St3); + res = eet_data_descriptor_stream_new(&eddc); + EET_DATA_DESCRIPTOR_ADD_BASIC(res, Eet_St3, "boby", boby, EET_T_INT); + + return res; +} + +static void +_eet_st3_set(Eet_St3 *st3, int i) +{ + st3->boby = EET_TEST_INT + i; +} + +static void +_eet_st3_cmp(Eet_St3 *st3, int i) +{ + fail_if(st3->boby != EET_TEST_INT + i); +} + +START_TEST(eet_test_union) +{ + Eet_Union_Test *eut; + Eet_List *l; + Eet_Data_Descriptor_Class eddc; + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor *unified; + Eet_Data_Descriptor *m; + void *blob; + int size; + int i; + + eina_init(); + eet_init(); + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_Union_Test); + edd = eet_data_descriptor_stream_new(&eddc); + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_Union_Test); + m = eet_data_descriptor_stream_new(&eddc); + + eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION; + eddc.func.type_get = _eet_union_type_get; + eddc.func.type_set = _eet_union_type_set; + unified = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST1", _eet_st1_dd()); + EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST2", _eet_st2_dd()); + EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST3", _eet_st3_dd()); + + EET_DATA_DESCRIPTOR_ADD_UNION(edd, Eet_Union_Test, "u", u, type, unified); + + EET_DATA_DESCRIPTOR_ADD_LIST(m, Eet_List, "list", list, edd); + + l = calloc(1, sizeof (Eet_List)); + +#define EUT_NEW(Type_Index) \ + eut = calloc(1, sizeof (Eet_Union_Test)); \ + eut->type = EET_ST##Type_Index; \ + _eet_st##Type_Index##_set(&(eut->u.st##Type_Index), i); + + for (i = 0; i < 3; ++i) + { + EUT_NEW(1); + l->list = eina_list_append(l->list, eut); + + EUT_NEW(2); + l->list = eina_list_append(l->list, eut); + + EUT_NEW(3); + l->list = eina_list_append(l->list, eut); + } + + blob = eet_data_descriptor_encode(m, l, &size); + fail_if(!blob || size <= 0); + + l = eet_data_descriptor_decode(m, blob, size); + fail_if(!l); + + fail_if(eina_list_count(l->list) != 9); + +#define EUT_CMP(Type_Index) \ + eut = eina_list_nth(l->list, i * 3 + Type_Index - 1); \ + fail_if(eut->type != EET_ST##Type_Index); \ + _eet_st##Type_Index##_cmp(&(eut->u.st##Type_Index), i); + + for (i = 0; i < 3; ++i) + { + EUT_CMP(1); + EUT_CMP(2); + EUT_CMP(3); + } + + eet_shutdown(); + eina_shutdown(); +} +END_TEST + +START_TEST(eet_test_variant) +{ + Eet_Variant_Test *evt; + Eet_List *l; + Eet_St1 *st1; + Eet_St2 *st2; + Eet_St3 *st3; + Eet_Data_Descriptor_Class eddc; + Eet_Data_Descriptor *edd; + Eet_Data_Descriptor *unified; + Eet_Data_Descriptor *m; + void *blob; + int size; + int i; + + eina_init(); + eet_init(); + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_Variant_Test); + edd = eet_data_descriptor_stream_new(&eddc); + + EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, Eet_Variant_Test); + m = eet_data_descriptor_stream_new(&eddc); + + eddc.version = EET_DATA_DESCRIPTOR_CLASS_VERSION; + eddc.func.type_get = _eet_variant_type_get; + eddc.func.type_set = _eet_variant_type_set; + unified = eet_data_descriptor_stream_new(&eddc); + + EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST1", _eet_st1_dd()); + EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST2", _eet_st2_dd()); + EET_DATA_DESCRIPTOR_ADD_MAPPING(unified, "ST3", _eet_st3_dd()); + + EET_DATA_DESCRIPTOR_ADD_VARIANT(edd, Eet_Variant_Test, "data", data, t, unified); + + unified = eet_data_descriptor_stream_new(&eddc); + eet_data_descriptor_element_add(unified, "ST1", + EET_T_UNKNOW, EET_G_LIST, + 0, 0, NULL, _eet_st1_dd()); + eet_data_descriptor_element_add(unified, "ST2", + EET_T_UNKNOW, EET_G_LIST, + 0, 0, NULL, _eet_st2_dd()); + + EET_DATA_DESCRIPTOR_ADD_VARIANT(edd, Eet_Variant_Test, + "data_list", data_list, t, unified); + + EET_DATA_DESCRIPTOR_ADD_LIST(m, Eet_List, "list", list, edd); + + l = calloc(1, sizeof (Eet_List)); + +#define EVT_NEW(Type_Index) \ + evt = calloc(1, sizeof (Eet_Variant_Test)); \ + evt->t.type = eet_mapping[Type_Index - 1].name; \ + st##Type_Index = calloc(1, sizeof (Eet_St##Type_Index)); \ + _eet_st##Type_Index##_set(st##Type_Index, i); \ + evt->data = st##Type_Index; + + for (i = 0; i < 3; ++i) + { + EVT_NEW(1); + l->list = eina_list_append(l->list, evt); + + st1 = calloc(1, sizeof (Eet_St1)); + _eet_st1_set(st1, i); + evt->data_list = eina_list_append(evt->data_list, st1); + + EVT_NEW(2); + l->list = eina_list_append(l->list, evt); + + EVT_NEW(3); + l->list = eina_list_append(l->list, evt); + } + + blob = eet_data_descriptor_encode(m, l, &size); + fail_if(!blob || size <= 0); + + l = eet_data_descriptor_decode(m, blob, size); + fail_if(!l); + + fail_if(eina_list_count(l->list) != 9); + +#define EVT_CMP(Type_Index) \ + evt = eina_list_nth(l->list, i * 3 + Type_Index - 1); \ + fail_if(strcmp(evt->t.type, eet_mapping[Type_Index - 1].name) != 0); \ + _eet_st##Type_Index##_cmp(evt->data, i); + + for (i = 0; i < 3; ++i) + { + EVT_CMP(1); + + fail_if(!evt->data_list); + fail_if(eina_list_count(evt->data_list) != 1); + + st1 = eina_list_data_get(evt->data_list); + _eet_st1_cmp(st1, i); + + EVT_CMP(2); + EVT_CMP(3); + } + + eet_shutdown(); + eina_shutdown(); +} +END_TEST + Suite * eet_suite(void) { @@ -1773,6 +2197,8 @@ tcase_add_test(tc, eet_test_data_type_encoding_decoding); tcase_add_test(tc, eet_test_data_type_dump_undump); tcase_add_test(tc, eet_fp); + tcase_add_test(tc, eet_test_union); + tcase_add_test(tc, eet_test_variant); suite_add_tcase(s, tc); tc = tcase_create("Eet File"); |
From: Enlightenment S. <no-...@en...> - 2010-06-29 16:20:31
|
Log: * eet: add support for eet_alias. Author: cedric Date: 2010-06-29 09:20:23 -0700 (Tue, 29 Jun 2010) New Revision: 49939 Modified: trunk/eet/ChangeLog trunk/eet/src/lib/Eet.h trunk/eet/src/lib/eet_lib.c trunk/eet/src/tests/eet_suite.c Modified: trunk/eet/ChangeLog =================================================================== --- trunk/eet/ChangeLog 2010-06-29 15:22:18 UTC (rev 49938) +++ trunk/eet/ChangeLog 2010-06-29 16:20:23 UTC (rev 49939) @@ -389,3 +389,8 @@ * On Windows 64, long is of size 32 bits and not 64 bits. Also LONG_BIT is not defined on Windows. + +2010-06-29 Cedric BAIL + + * Add eet_alias support. + * Fix possible dead lock in eet_write_cipher. Modified: trunk/eet/src/lib/Eet.h =================================================================== --- trunk/eet/src/lib/Eet.h 2010-06-29 15:22:18 UTC (rev 49938) +++ trunk/eet/src/lib/Eet.h 2010-06-29 16:20:23 UTC (rev 49939) @@ -445,6 +445,23 @@ EAPI int eet_delete(Eet_File *ef, const char *name); /** + * Alias a specific section to another one. Destination may exist or not, + * no check are done. + * @param ef A valid eet file handle opened for writing. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param destination Destionation of the alias. eg: "/base/the_real_stuff_i_want". + * @param compress Compression flags (1 == compress, 0 = don't compress). + * @return EINA_TRUE on success, EINA_FALSE on failure. + * + * Name and Destination must not be NULL, otherwhise EINA_FALSE will be returned. + * + * @since 1.3.3 + * @ingroup Eet_File_Group + */ + EAPI Eina_Bool eet_alias(Eet_File *ef, const char *name, const char *destination, int compress); + + + /** * List all entries in eet file matching shell glob. * @param ef A valid eet file handle. * @param glob A shell glob to match against. Modified: trunk/eet/src/lib/eet_lib.c =================================================================== --- trunk/eet/src/lib/eet_lib.c 2010-06-29 15:22:18 UTC (rev 49938) +++ trunk/eet/src/lib/eet_lib.c 2010-06-29 16:20:23 UTC (rev 49939) @@ -146,6 +146,7 @@ unsigned char free_name : 1; unsigned char compression : 1; unsigned char ciphered : 1; + unsigned char alias : 1; }; #if 0 @@ -181,7 +182,11 @@ int data_size; /* size of the (uncompressed) data chunk */ int name_offset; /* bytes offset into file for name string */ int name_size; /* length in bytes of the name field */ - int flags; /* flags - for now 0 = uncompressed, 1 = compressed */ + int flags; /* bit flags - for now: + bit 0 => compresion on/off + bit 1 => ciphered on/off + bit 2 => alias + */ } directory[num_directory_entries]; struct { @@ -521,7 +526,7 @@ unsigned int flag; int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT]; - flag = (efn->ciphered << 1) | efn->compression; + flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression; ibuf[0] = (int) htonl ((unsigned int) efn->offset); ibuf[1] = (int) htonl ((unsigned int) efn->size); @@ -889,6 +894,7 @@ efn->compression = flag & 0x1 ? 1 : 0; efn->ciphered = flag & 0x2 ? 1 : 0; + efn->alias = flag & 0x4 ? 1 : 0; #define EFN_TEST(Test, Ef, Efn) \ if (eet_test_close(Test, Ef)) \ @@ -1120,6 +1126,7 @@ efn->name_size = name_size; efn->ciphered = 0; + efn->alias = 0; /* invalid size */ if (eet_test_close(efn->size <= 0, ef)) @@ -1570,9 +1577,9 @@ EAPI void * eet_read_cipher(Eet_File *ef, const char *name, int *size_ret, const char *cipher_key) { - void *data = NULL; - int size = 0; - Eet_File_Node *efn; + Eet_File_Node *efn; + char *data = NULL; + int size = 0; if (size_ret) *size_ret = 0; @@ -1609,6 +1616,7 @@ void *data_deciphered = NULL; unsigned int data_deciphered_sz = 0; /* if we alreayd have the data in ram... copy that */ + if (efn->data) memcpy(data, efn->data, efn->size); else @@ -1677,12 +1685,27 @@ free(tmp_data); } - /* fill in return values */ - if (size_ret) - *size_ret = size; - UNLOCK_FILE(ef); + /* handle alias */ + if (efn->alias) + { + void *tmp; + + if (data[size - 1] != '\0') + goto on_error; + + tmp = eet_read_cipher(ef, data, size_ret, cipher_key); + + free(data); + + data = tmp; + } + else + /* fill in return values */ + if (size_ret) + *size_ret = size; + return data; on_error: @@ -1700,9 +1723,9 @@ EAPI const void * eet_read_direct(Eet_File *ef, const char *name, int *size_ret) { - const void *data = NULL; - int size = 0; Eet_File_Node *efn; + const char *data = NULL; + int size = 0; if (size_ret) *size_ret = 0; @@ -1732,13 +1755,42 @@ /* get size (uncompressed, if compressed at all) */ size = efn->data_size; - /* uncompressed data */ - if (efn->compression == 0 - && efn->ciphered == 0) - data = efn->data ? efn->data : ef->data + efn->offset; + if (efn->alias) + { + data = efn->data ? efn->data : ef->data + efn->offset; + + /* handle alias case */ + if (efn->compression) + { + char *tmp; + int compr_size = efn->size; + uLongf dlen; + + tmp = alloca(sizeof (compr_size)); + dlen = size; + + if (uncompress((Bytef *)tmp, &dlen, (Bytef *) data, (uLongf)compr_size)) + goto on_error; + + if (tmp[compr_size - 1] != '\0') + goto on_error; + + return eet_read_direct(ef, tmp, size_ret); + } + + if (!data) goto on_error; + if (data[size - 1] != '\0') goto on_error; + + return eet_read_direct(ef, data, size_ret); + } + else + /* uncompressed data */ + if (efn->compression == 0 + && efn->ciphered == 0) + data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */ - else - data = NULL; + else + data = NULL; /* fill in return values */ if (size_ret) @@ -1753,6 +1805,150 @@ return NULL; } +EAPI Eina_Bool +eet_alias(Eet_File *ef, const char *name, const char *destination, int comp) +{ + Eet_File_Node *efn; + void *data2; + Eina_Bool exists_already = EINA_FALSE; + int data_size; + int hash; + + /* check to see its' an eet file pointer */ + if (eet_check_pointer(ef)) + return EINA_FALSE; + if ((!name) || (!destination)) + return EINA_FALSE; + if ((ef->mode != EET_FILE_MODE_WRITE) && + (ef->mode != EET_FILE_MODE_READ_WRITE)) + return EINA_FALSE; + + LOCK_FILE(ef); + + if (!ef->header) + { + /* allocate header */ + ef->header = calloc(1, sizeof(Eet_File_Header)); + if (!ef->header) + goto on_error; + + ef->header->magic = EET_MAGIC_FILE_HEADER; + /* allocate directory block in ram */ + ef->header->directory = calloc(1, sizeof(Eet_File_Directory)); + if (!ef->header->directory) + { + free(ef->header); + ef->header = NULL; + goto on_error; + } + + /* 8 bit hash table (256 buckets) */ + ef->header->directory->size = 8; + /* allocate base hash table */ + ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size)); + if (!ef->header->directory->nodes) + { + free(ef->header->directory); + ef->header = NULL; + goto on_error; + } + } + + /* figure hash bucket */ + hash = _eet_hash_gen(name, ef->header->directory->size); + + data_size = comp ? + 12 + (((strlen(destination) + 1) * 101) / 100) + : strlen(destination) + 1; + + data2 = malloc(data_size); + if (!data2) goto on_error; + + /* if we want to compress */ + if (comp) + { + uLongf buflen; + + /* compress the data with max compression */ + buflen = (uLongf)data_size; + if (compress2((Bytef *)data2, &buflen, (Bytef *)destination, + (uLong)strlen(destination) + 1, Z_BEST_COMPRESSION) != Z_OK) + { + free(data2); + goto on_error; + } + /* record compressed chunk size */ + data_size = (int)buflen; + if (data_size < 0 || data_size >= (int) (strlen(destination) + 1)) + { + comp = 0; + data_size = strlen(destination) + 1; + } + else + { + void *data3; + + data3 = realloc(data2, data_size); + if (data3) + data2 = data3; + } + } + + if (!comp) + memcpy(data2, destination, data_size); + + /* Does this node already exist? */ + for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next) + { + /* if it matches */ + if ((efn->name) && (eet_string_match(efn->name, name))) + { + free(efn->data); + efn->alias = 1; + efn->ciphered = 0; + efn->compression = !!comp; + efn->size = data_size; + efn->data_size = strlen(destination) + 1; + efn->data = data2; + efn->offset = -1; + exists_already = EINA_TRUE; + break; + } + } + if (!exists_already) + { + efn = malloc(sizeof(Eet_File_Node)); + if (!efn) + { + free(data2); + goto on_error; + } + efn->name = strdup(name); + efn->name_size = strlen(efn->name) + 1; + efn->free_name = 1; + + efn->next = ef->header->directory->nodes[hash]; + ef->header->directory->nodes[hash] = efn; + efn->offset = -1; + efn->alias = 1; + efn->ciphered = 0; + efn->compression = !!comp; + efn->size = data_size; + efn->data_size = strlen(destination) + 1; + efn->data = data2; + } + + /* flags that writes are pending */ + ef->writes_pending = 1; + + UNLOCK_FILE(ef); + return EINA_TRUE; + + on_error: + UNLOCK_FILE(ef); + return EINA_FALSE; +} + EAPI int eet_write_cipher(Eet_File *ef, const char *name, const void *data, int size, int comp, const char *cipher_key) { @@ -1824,7 +2020,7 @@ (uLong)size, Z_BEST_COMPRESSION) != Z_OK) { free(data2); - return 0; + goto on_error; } /* record compressed chunk size */ data_size = (int)buflen; @@ -1874,6 +2070,7 @@ if ((efn->name) && (eet_string_match(efn->name, name))) { free(efn->data); + efn->alias = 0; efn->ciphered = cipher_key ? 1 : 0; efn->compression = !!comp; efn->size = data_size; @@ -1899,6 +2096,7 @@ efn->next = ef->header->directory->nodes[hash]; ef->header->directory->nodes[hash] = efn; efn->offset = -1; + efn->alias = 0; efn->ciphered = cipher_key ? 1 : 0; efn->compression = !!comp; efn->size = data_size; Modified: trunk/eet/src/tests/eet_suite.c =================================================================== --- trunk/eet/src/tests/eet_suite.c 2010-06-29 15:22:18 UTC (rev 49938) +++ trunk/eet/src/tests/eet_suite.c 2010-06-29 16:20:23 UTC (rev 49939) @@ -364,7 +364,7 @@ static Eet_Test_Ex_Type* _eet_test_ex_set(Eet_Test_Ex_Type *res, int offset) { - int i; + unsigned int i; if (!res) res = malloc( sizeof(Eet_Test_Ex_Type)); if (!res) return NULL; @@ -671,6 +671,8 @@ fail_if(!ef); fail_if(!eet_write(ef, "keys/tests", buffer, strlen(buffer) + 1, 1)); + fail_if(!eet_alias(ef, "keys/alias", "keys/tests", 0)); + fail_if(!eet_alias(ef, "keys/alias2", "keys/alias", 1)); fail_if(eet_mode_get(ef) != EET_FILE_MODE_WRITE); @@ -689,8 +691,14 @@ fail_if(memcmp(test, buffer, strlen(buffer) + 1) != 0); + test = eet_read(ef, "keys/alias2", &size); + fail_if(!test); + fail_if(size != (int) strlen(buffer) + 1); + + fail_if(eet_read_direct(ef, "key/alias2", &size)); + fail_if(eet_mode_get(ef) != EET_FILE_MODE_READ); - fail_if(eet_num_entries(ef) != 1); + fail_if(eet_num_entries(ef) != 3); eet_close(ef); @@ -1324,7 +1332,7 @@ { memset(pass, 0, size); - if (strlen("password") > size) + if ((int) strlen("password") > size) return 0; snprintf(pass, size, "%s", "password"); return strlen(pass); @@ -1334,7 +1342,7 @@ { memset(pass, 0, size); - if (strlen("bad password") > size) + if ((int) strlen("bad password") > size) return 0; snprintf(pass, size, "%s", "bad password"); return strlen(pass); |
From: Enlightenment S. <no-...@en...> - 2010-08-13 15:22:03
|
Log: * eet: fix bad allocation case triggered by edje new file format. Bad news, I also discovered in the same time that we introduced an API/ABI breakage in 1.3.0. This patch does prevent it from coming again, sadly, it imply an ABI break that I didn't find a proper way to work around. So recompile eet and all the program that use it after that commit. Author: cedric Date: 2010-08-13 08:21:52 -0700 (Fri, 13 Aug 2010) New Revision: 51080 Modified: trunk/eet/ChangeLog trunk/eet/src/lib/Eet.h trunk/eet/src/lib/eet_data.c trunk/eet/src/tests/eet_data_suite.c trunk/eet/src/tests/eet_suite.c Modified: trunk/eet/ChangeLog =================================================================== --- trunk/eet/ChangeLog 2010-08-13 14:34:36 UTC (rev 51079) +++ trunk/eet/ChangeLog 2010-08-13 15:21:52 UTC (rev 51080) @@ -418,3 +418,11 @@ * Add EET_DATA_DESCRIPTOR_ADD_HASH_STRING. +2010-08-06 Cedric BAIL + + * Break eet_eina_* function helper to provide a clean API/ABI to + prevent futur break. This should prevent the ABI break that was + introduced with release 1.3.0. + + * Add a specific allocator for array. This should fix wrong allocation + case discovered with recent edje file format change. Modified: trunk/eet/src/lib/Eet.h =================================================================== --- trunk/eet/src/lib/Eet.h 2010-08-13 14:34:36 UTC (rev 51079) +++ trunk/eet/src/lib/Eet.h 2010-08-13 15:21:52 UTC (rev 51080) @@ -1736,7 +1736,7 @@ * version member so it is compatible with abi changes, or at least * will not crash with them. */ -#define EET_DATA_DESCRIPTOR_CLASS_VERSION 3 +#define EET_DATA_DESCRIPTOR_CLASS_VERSION 4 /** * @typedef Eet_Data_Descriptor_Class @@ -1778,6 +1778,8 @@ void (*str_direct_free)(const char *str); /**< how to free a string returned by str_direct_alloc */ const char *(*type_get)(const void *data, Eina_Bool *unknow); /**< convert any kind of data type to a name that define an Eet_Data_Element. */ Eina_Bool (*type_set)(const char *type, void *data, Eina_Bool unknow); /**< set the type at a particular adress */ + void * (*array_alloc)(size_t size); /**< how to allocate memory for array (usually malloc()) */ + void (*array_free)(void *mem); /**< how to free memory for array (usually malloc()) */ } func; }; @@ -1914,6 +1916,7 @@ * @ingroup Eet_Data_Group */ EAPI Eina_Bool eet_eina_stream_data_descriptor_class_set(Eet_Data_Descriptor_Class *eddc, + unsigned int eddc_size, const char *name, int size); @@ -1931,7 +1934,7 @@ * @ingroup Eet_Data_Group */ #define EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(clas, type)\ - (eet_eina_stream_data_descriptor_class_set(clas, # type, sizeof(type))) + (eet_eina_stream_data_descriptor_class_set(clas, sizeof (*(clas)), # type, sizeof(type))) /** * This function is an helper that set all the parameter of an @@ -1948,6 +1951,7 @@ * @ingroup Eet_Data_Group */ EAPI Eina_Bool eet_eina_file_data_descriptor_class_set(Eet_Data_Descriptor_Class *eddc, + unsigned int eddc_size, const char *name, int size); @@ -1964,8 +1968,8 @@ * @since 1.2.3 * @ingroup Eet_Data_Group */ -#define EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(clas, type) (\ - eet_eina_file_data_descriptor_class_set(clas, # type, sizeof(type))) +#define EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(clas, type)\ + (eet_eina_file_data_descriptor_class_set(clas, sizeof (*(clas)), # type, sizeof(type))) /** * This function frees a data descriptor when it is not needed anymore. Modified: trunk/eet/src/lib/eet_data.c =================================================================== --- trunk/eet/src/lib/eet_data.c 2010-08-13 14:34:36 UTC (rev 51079) +++ trunk/eet/src/lib/eet_data.c 2010-08-13 15:21:52 UTC (rev 51080) @@ -138,6 +138,8 @@ 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 { @@ -186,6 +188,7 @@ struct _Eet_Free_Context { Eet_Free freelist; + Eet_Free freelist_array; Eet_Free freelist_list; Eet_Free freelist_hash; Eet_Free freelist_str; @@ -1670,10 +1673,12 @@ /*---*/ 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) + if (!eddc || !name || eddc_size != sizeof (Eet_Data_Descriptor_Class)) return EINA_FALSE; eddc->name = name; @@ -1692,15 +1697,21 @@ eddc->func.hash_add = (void * (*)(void *, const char *, void *))_eet_eina_hash_add_alloc; eddc->func.hash_free = (void (*)(void *))_eet_eina_hash_free; + /* This will cause an ABI incompatibility */ + eddc->func.array_alloc = _eet_mem_alloc; + eddc->func.array_free = _eet_mem_free; + return EINA_TRUE; } /* eet_eina_stream_data_descriptor_class_set */ EAPI Eina_Bool eet_eina_file_data_descriptor_class_set(Eet_Data_Descriptor_Class *eddc, + /* When we change the structure content in the future, we need to handle old structure type too */ + unsigned int eddc_size, const char *name, int size) { - if (!eet_eina_stream_data_descriptor_class_set(eddc, name, size)) + if (!eet_eina_stream_data_descriptor_class_set(eddc, eddc_size, name, size)) return EINA_FALSE; eddc->version = 2; @@ -1764,6 +1775,12 @@ edd->func.type_set = eddc->func.type_set; } + if (eddc->version > 3) + { + edd->func.array_alloc = eddc->func.array_alloc; + edd->func.array_free = eddc->func.array_free; + } + return edd; } /* _eet_data_descriptor_new */ @@ -2154,6 +2171,37 @@ _eet_free_reset(&context->freelist); } /* _eet_freelist_free */ +#define _eet_freelist_array_add(Ctx, Data) _eet_free_add(&Ctx->freelist_array, Data); +#define _eet_freelist_array_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) +{ + int j; + int i; + + if (context->freelist_array.ref > 0) + return; + + for (j = 0; j < 256; ++j) + for (i = 0; i < context->freelist_array.num[j]; ++i) + { + if (edd) + { + if (edd->func.array_free) + edd->func.array_free(context->freelist_array.list[j][i]); + else + edd->func.mem_free(context->freelist_array.list[j][i]); + } + else + free(context->freelist_array.list[j][i]); + } + _eet_free_reset(&context->freelist_array); +} /* _eet_freelist_array_free */ + #define _eet_freelist_list_add(Ctx, Data) _eet_free_add(&Ctx->freelist_list, Data); #define _eet_freelist_list_reset(Ctx) _eet_free_reset(&Ctx->freelist_list); #define _eet_freelist_list_ref(Ctx) _eet_free_ref(&Ctx->freelist_list); @@ -3224,6 +3272,7 @@ _eet_freelist_direct_str_free(context, edd); _eet_freelist_list_free(context, edd); _eet_freelist_hash_free(context, edd); + _eet_freelist_array_free(context, edd); _eet_freelist_free(context, edd); } else @@ -3233,6 +3282,7 @@ _eet_freelist_list_reset(context); _eet_freelist_hash_reset(context); _eet_freelist_direct_str_reset(context); + _eet_freelist_array_reset(context); } if (!edd) @@ -3248,6 +3298,7 @@ _eet_freelist_direct_str_free(context, edd); _eet_freelist_list_free(context, edd); _eet_freelist_hash_free(context, edd); + _eet_freelist_array_free(context, edd); _eet_freelist_free(context, edd); /* FIXME: Warn that something goes wrong here. */ @@ -3454,14 +3505,17 @@ * on the counter offset */ *(int *)(((char *)data) + ede->count - ede->offset) = count; /* allocate space for the array of elements */ - *(void **)ptr = edd->func.mem_alloc(count * subsize); + if (edd->func.array_alloc) + *(void **) ptr = edd->func.array_alloc(count * subsize); + else + *(void **) ptr = edd->func.mem_alloc(count * subsize); if (!*(void **)ptr) return 0; memset(*(void **)ptr, 0, count * subsize); - _eet_freelist_add(context, *(void **)ptr); + _eet_freelist_array_add(context, *(void **)ptr); } } Modified: trunk/eet/src/tests/eet_data_suite.c =================================================================== --- trunk/eet/src/tests/eet_data_suite.c 2010-08-13 14:34:36 UTC (rev 51079) +++ trunk/eet/src/tests/eet_data_suite.c 2010-08-13 15:21:52 UTC (rev 51080) @@ -63,5 +63,7 @@ eddc->func.hash_free = (void *)_eet_eina_hash_free; eddc->func.str_direct_alloc = (void *)_eet_str_direct_alloc; eddc->func.str_direct_free = (void *)_eet_str_direct_free; + eddc->func.array_alloc = NULL; + eddc->func.array_free = NULL; } /* eet_test_setup_eddc */ Modified: trunk/eet/src/tests/eet_suite.c =================================================================== --- trunk/eet/src/tests/eet_suite.c 2010-08-13 14:34:36 UTC (rev 51079) +++ trunk/eet/src/tests/eet_suite.c 2010-08-13 15:21:52 UTC (rev 51080) @@ -1121,7 +1121,8 @@ memset(&etbt.charray, 0, sizeof(etbt.charray)); etbt.charray[0] = "test"; - eet_eina_file_data_descriptor_class_set(&eddc, "Eet_Test_Ex_Type", + eet_eina_file_data_descriptor_class_set(&eddc, sizeof (eddc), + "Eet_Test_Ex_Type", sizeof(Eet_Test_Ex_Type)); edd = eet_data_descriptor_file_new(&eddc); @@ -2041,7 +2042,8 @@ memset(&etbt.charray, 0, sizeof(etbt.charray)); etbt.charray[0] = "test"; - eet_eina_file_data_descriptor_class_set(&eddc, "Eet_Test_Ex_Type", + eet_eina_file_data_descriptor_class_set(&eddc, sizeof (eddc), + "Eet_Test_Ex_Type", sizeof(Eet_Test_Ex_Type)); edd = eet_data_descriptor_file_new(&eddc); @@ -2113,7 +2115,7 @@ EET_DATA_DESCRIPTOR_ADD_BASIC(edd_5FP, Eet_5FP, "f1", f1, EET_T_F32P32); EET_DATA_DESCRIPTOR_ADD_BASIC(edd_5FP, Eet_5FP, "f0", f0, EET_T_F32P32); - eet_eina_stream_data_descriptor_class_set(&eddc, "Eet_5FP", sizeof (Eet_5DBL)); + eet_eina_stream_data_descriptor_class_set(&eddc, sizeof (eddc), "Eet_5FP", sizeof (Eet_5DBL)); edd_5DBL = eet_data_descriptor_stream_new(&eddc); EET_DATA_DESCRIPTOR_ADD_BASIC(edd_5DBL, Eet_5DBL, "fp32", fp32, EET_T_DOUBLE); @@ -2175,7 +2177,7 @@ EET_DATA_DESCRIPTOR_ADD_BASIC(edd_5FP, Eet_5FP, "f1", f1, EET_T_F32P32); EET_DATA_DESCRIPTOR_ADD_BASIC(edd_5FP, Eet_5FP, "f0", f0, EET_T_F32P32); - eet_eina_file_data_descriptor_class_set(&eddc, "Eet_5FP", sizeof (Eet_5DBL)); + eet_eina_file_data_descriptor_class_set(&eddc, sizeof (eddc), "Eet_5FP", sizeof (Eet_5DBL)); edd_5DBL = eet_data_descriptor_file_new(&eddc); EET_DATA_DESCRIPTOR_ADD_BASIC(edd_5DBL, Eet_5DBL, "fp32", fp32, EET_T_DOUBLE); |
From: Enlightenment S. <no-...@en...> - 2011-05-17 16:20:00
|
Log: eet: use Eina_File and fix forgotten init in Eet test suite. Author: cedric Date: 2011-05-17 09:19:53 -0700 (Tue, 17 May 2011) New Revision: 59471 Trac: http://trac.enlightenment.org/e/changeset/59471 Modified: trunk/eet/ChangeLog trunk/eet/src/lib/eet_lib.c trunk/eet/src/tests/eet_suite.c Modified: trunk/eet/ChangeLog =================================================================== --- trunk/eet/ChangeLog 2011-05-17 16:17:28 UTC (rev 59470) +++ trunk/eet/ChangeLog 2011-05-17 16:19:53 UTC (rev 59471) @@ -496,3 +496,8 @@ * Use Eina_Lock. * Sync GNUTLS initialisation with Eina. + +2011-05-17 Cedric BAIL + + * Use Eina_File. + * Fix test forgetting to initialize eet. Modified: trunk/eet/src/lib/eet_lib.c =================================================================== --- trunk/eet/src/lib/eet_lib.c 2011-05-17 16:17:28 UTC (rev 59470) +++ trunk/eet/src/lib/eet_lib.c 2011-05-17 16:19:53 UTC (rev 59471) @@ -86,7 +86,7 @@ struct _Eet_File { char *path; - FILE *readfp; + Eina_File *readfp; Eet_File_Header *header; Eet_Dictionary *ed; Eet_Key *key; @@ -100,13 +100,11 @@ int magic; int references; - int data_size; + unsigned long int data_size; int x509_length; unsigned int signature_length; int sha1_length; - time_t mtime; - Eina_Lock file_lock; unsigned char writes_pending : 1; @@ -131,13 +129,13 @@ void *data; Eet_File_Node *next; /* FIXME: make buckets linked lists */ - int offset; - int dictionary_offset; - int name_offset; + unsigned long int offset; + unsigned long int dictionary_offset; + unsigned long int name_offset; - int name_size; - int size; - int data_size; + unsigned int name_size; + unsigned int size; + unsigned int data_size; unsigned char free_name : 1; unsigned char compression : 1; @@ -850,12 +848,12 @@ const int *data = (const int *)ef->data; const char *start = (const char *)ef->data; int idx = 0; - int num_directory_entries; - int bytes_directory_entries; - int num_dictionary_entries; - int bytes_dictionary_entries; - int signature_base_offset; - int i; + unsigned long int bytes_directory_entries; + unsigned long int bytes_dictionary_entries; + unsigned long int signature_base_offset; + unsigned long int num_directory_entries; + unsigned long int num_dictionary_entries; + unsigned int i; idx += sizeof(int); if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef)) @@ -916,8 +914,8 @@ { const char *name; Eet_File_Node *efn; - int name_offset; - int name_size; + unsigned long int name_offset; + unsigned long int name_size; int hash; int flag; @@ -1022,8 +1020,8 @@ for (j = 0; j < ef->ed->count; ++j) { + unsigned int offset; int hash; - int offset; GET_INT(hash, dico, idx); GET_INT(offset, dico, idx); @@ -1104,10 +1102,10 @@ { const unsigned char *dyn_buf = NULL; const unsigned char *p = NULL; + unsigned long int byte_entries; + unsigned long int num_entries; + unsigned int i; int idx = 0; - int num_entries; - int byte_entries; - int i; WRN( "EET file format of '%s' is deprecated. You should just open it one time with mode == EET_FILE_MODE_READ_WRITE to solve this issue.", @@ -1334,7 +1332,13 @@ ef->references--; /* if its still referenced - dont go any further */ if (ef->references > 0) - goto on_error; /* flush any writes */ + { + /* flush any writes */ + if ((ef->mode == EET_FILE_MODE_WRITE) || + (ef->mode == EET_FILE_MODE_READ_WRITE)) + eet_sync(ef); + goto on_error; + } err = eet_flush2(ef); @@ -1349,10 +1353,7 @@ if (ef->mode == EET_FILE_MODE_READ) eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); else if ((ef->mode == EET_FILE_MODE_WRITE) || - ( - ef - -> - mode == EET_FILE_MODE_READ_WRITE)) + (ef->mode == EET_FILE_MODE_READ_WRITE)) eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); /* we can unlock the cache now */ @@ -1400,13 +1401,13 @@ eet_dictionary_free(ef->ed); if (ef->sha1) - free(ef->sha1); + free(ef->sha1); if (ef->data) - munmap((void *)ef->data, ef->data_size); + eina_file_map_free(ef->readfp, (void *) ef->data); if (ef->readfp) - fclose(ef->readfp); + eina_file_close(ef->readfp); /* zero out ram for struct - caution tactic against stale memory use */ memset(ef, 0, sizeof(Eet_File)); @@ -1443,7 +1444,6 @@ ef->references = 1; ef->mode = EET_FILE_MODE_READ; ef->header = NULL; - ef->mtime = 0; ef->delete_me_now = 1; ef->readfp = NULL; ef->data = data; @@ -1462,10 +1462,10 @@ eet_open(const char *file, Eet_File_Mode mode) { - FILE *fp; + Eina_File *fp; Eet_File *ef; int file_len; - struct stat file_stat; + unsigned long int size; if (!file) return NULL; @@ -1504,28 +1504,18 @@ if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE)) { /* Prevent garbage in futur comparison. */ - file_stat.st_mtime = 0; - - fp = fopen(file, "rb"); + fp = eina_file_open(file, EINA_FALSE); if (!fp) goto open_error; - if (fstat(fileno(fp), &file_stat)) - { - fclose(fp); - fp = NULL; + size = eina_file_size_get(fp); - memset(&file_stat, 0, sizeof(file_stat)); - - goto open_error; - } - - if (file_stat.st_size < ((int)sizeof(int) * 3)) + if (size < ((int)sizeof(int) * 3)) { - fclose(fp); + eina_file_close(fp); fp = NULL; - memset(&file_stat, 0, sizeof(file_stat)); + size = 0; goto open_error; } @@ -1539,15 +1529,13 @@ if (mode != EET_FILE_MODE_WRITE) return NULL; - memset(&file_stat, 0, sizeof(file_stat)); + size = 0; fp = NULL; } /* We found one */ - if (ef && - ((file_stat.st_mtime != ef->mtime) || - (file_stat.st_size != ef->data_size))) + if (ef && ef->readfp != fp) { ef->delete_me_now = 1; ef->references++; @@ -1559,7 +1547,7 @@ { /* reference it up and return it */ if (fp) - fclose(fp); + eina_file_close(fp); ef->references++; UNLOCK_CACHE; @@ -1583,7 +1571,6 @@ ef->references = 1; ef->mode = mode; ef->header = NULL; - ef->mtime = file_stat.st_mtime; ef->writes_pending = 0; ef->delete_me_now = 0; ef->data = NULL; @@ -1603,14 +1590,12 @@ if (eet_test_close(!ef->readfp, ef)) goto on_error; - fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC); /* if we opened for read or read-write */ if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE)) { - ef->data_size = file_stat.st_size; - ef->data = mmap(NULL, ef->data_size, PROT_READ, - MAP_SHARED, fileno(ef->readfp), 0); - if (eet_test_close((ef->data == MAP_FAILED), ef)) + ef->data_size = size; + ef->data = eina_file_map_all(fp, EINA_FILE_SEQUENTIAL); + if (eet_test_close((ef->data == NULL), ef)) goto on_error; ef = eet_internal_read(ef); @@ -1623,11 +1608,10 @@ if (ef->references == 1) { if (ef->mode == EET_FILE_MODE_READ) - eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); - else - if ((ef->mode == EET_FILE_MODE_WRITE) || - (ef->mode == EET_FILE_MODE_READ_WRITE)) - eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); + eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); + else if ((ef->mode == EET_FILE_MODE_WRITE) || + (ef->mode == EET_FILE_MODE_READ_WRITE)) + eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); } UNLOCK_CACHE; @@ -1723,7 +1707,7 @@ { Eet_File_Node *efn; char *data = NULL; - int size = 0; + unsigned long int size = 0; if (size_ret) *size_ret = 0; @@ -1928,7 +1912,8 @@ if (!efn) goto on_error; - if (efn->offset < 0 && !efn->data) + /* trick to detect data in memory instead of mmaped from disk */ + if (efn->offset > ef->data_size && !efn->data) goto on_error; /* get size (uncompressed, if compressed at all) */ @@ -2106,8 +2091,10 @@ efn->size = data_size; efn->data_size = strlen(destination) + 1; efn->data = data2; - efn->offset = -1; + /* Put the offset above the limit to avoid direct access */ + efn->offset = ef->data_size + 1; exists_already = EINA_TRUE; + break; } } @@ -2126,7 +2113,8 @@ efn->next = ef->header->directory->nodes[hash]; ef->header->directory->nodes[hash] = efn; - efn->offset = -1; + /* Put the offset above the limit to avoid direct access */ + efn->offset = ef->data_size + 1; efn->alias = 1; efn->ciphered = 0; efn->compression = !!comp; @@ -2288,7 +2276,8 @@ efn->size = data_size; efn->data_size = size; efn->data = data2; - efn->offset = -1; + /* Put the offset above the limit to avoid direct access */ + efn->offset = ef->data_size + 1; exists_already = 1; break; } @@ -2308,7 +2297,8 @@ efn->next = ef->header->directory->nodes[hash]; ef->header->directory->nodes[hash] = efn; - efn->offset = -1; + /* Put the offset above the limit to avoid direct access */ + efn->offset = ef->data_size + 1; efn->alias = 0; efn->ciphered = cipher_key ? 1 : 0; efn->compression = !!comp; @@ -2544,29 +2534,17 @@ void *buf, int len) { - if (efn->offset < 0) + if (efn->offset > ef->data_size) return 0; - if (ef->data) - { - if ((efn->offset + len) > ef->data_size) - return 0; + if (!ef->data) + return 0; - memcpy(buf, ef->data + efn->offset, len); - } - else - { - if (!ef->readfp) - return 0; + if ((efn->offset + len) > ef->data_size) + return 0; - /* seek to data location */ - if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0) - return 0; + memcpy(buf, ef->data + efn->offset, len); - /* read it */ - len = fread(buf, len, 1, ef->readfp); - } - return len; } /* read_data_from_disk */ Modified: trunk/eet/src/tests/eet_suite.c =================================================================== --- trunk/eet/src/tests/eet_suite.c 2011-05-17 16:17:28 UTC (rev 59470) +++ trunk/eet/src/tests/eet_suite.c 2011-05-17 16:19:53 UTC (rev 59471) @@ -1018,6 +1018,12 @@ fail_if(!eet_data_write(ef, edd, EET_TEST_FILE_KEY1, &etbt, 0)); + result = eet_data_read(ef, edd, EET_TEST_FILE_KEY1); + fail_if(!result); + + /* Test the resulting data. */ + fail_if(_eet_test_ex_check(result, 0) != 0); + eet_close(ef); /* Read back the data. */ @@ -1204,6 +1210,8 @@ unsigned int w; unsigned int h; + eet_init(); + fail_if(!(file = tmpnam(file))); /* Save the encoded data in a file. */ |