diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h index d2f5d4543d..23366d629a 100644 --- a/src/lib/eina/Eina.h +++ b/src/lib/eina/Eina.h @@ -272,6 +272,7 @@ extern "C" { #include #include #include +#include #undef EAPI #define EAPI diff --git a/src/lib/eina/eina_abstract_content.c b/src/lib/eina/eina_abstract_content.c new file mode 100644 index 0000000000..4b74256d25 --- /dev/null +++ b/src/lib/eina/eina_abstract_content.c @@ -0,0 +1,443 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include "eina_abstract_content.h" + +struct _Eina_Content +{ + Eina_Rw_Slice data; + const char *type; + const char *file; + EINA_REFCOUNT; +}; +EAPI const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT; + +static int _eina_abstract_content_log_domain = -1; + +#ifdef ERR +#undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_eina_abstract_content_log_domain, __VA_ARGS__) + +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_eina_abstract_content_log_domain, __VA_ARGS__) + +static Eina_Hash *conversion_callbacks; + +typedef struct { + const char *to; + Eina_Content_Conversion_Callback callback; +} Eina_Content_Conversion_Node; + +static void +_eina_content_ref(Eina_Content *content) +{ + EINA_REFCOUNT_REF(content); +} + +EAPI Eina_Bool +eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback conversion) +{ + Eina_Content_Conversion_Node *node = calloc(1, sizeof(Eina_Content_Conversion_Node)); + + Eina_Stringshare *shared_from = eina_stringshare_add(from); + + if (eina_content_converter_convert_can(from, to)) + { + ERR("Convertion from %s to %s is already possible", from, to); + return EINA_FALSE; + } + + node->to = eina_stringshare_add(to); + node->callback = conversion; + + eina_hash_list_append(conversion_callbacks, shared_from, node); + + return EINA_TRUE; +} + +static inline Eina_List* +_conversion_callback_fetch_possible(const char *from) +{ + Eina_Stringshare *shared_from = eina_stringshare_add(from); + Eina_List *res = eina_hash_find(conversion_callbacks, shared_from); + eina_stringshare_del(shared_from); + return res; +} + +static inline Eina_Content_Conversion_Callback +_conversion_callback_fetch(const char *from, const char *to) +{ + Eina_List *possibilities = _conversion_callback_fetch_possible(from); + Eina_Content_Conversion_Node *n; + Eina_Content_Conversion_Callback result = NULL; + Eina_List *l; + Eina_Stringshare *shared_to = eina_stringshare_add(to); + + EINA_LIST_FOREACH(possibilities, l, n) + { + if (n->to == shared_to) + { + result = n->callback; + goto end; + } + } +end: + eina_stringshare_del(shared_to); + return result; +} + +EAPI Eina_Bool +eina_content_converter_convert_can(const char *from, const char *to) +{ + return !!_conversion_callback_fetch(from, to); +} + +static const void* +_process_cb(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED) +{ + Eina_Content_Conversion_Node *n = data; + + return n->to; + } + +EAPI Eina_Iterator* +eina_content_converter_possible_conversions(const char *from) +{ + Eina_List *possibilities = _conversion_callback_fetch_possible(from); + + return eina_iterator_processed_new(eina_list_iterator_new(possibilities) , EINA_PROCESS_CB(_process_cb), NULL, possibilities); +} + +EAPI Eina_Content* +eina_content_new(Eina_Slice data, const char *type) +{ + Eina_Content *content; + + if (!strncmp(type, "text", strlen("text"))) + { + //last char in the mem must be \0 + if (((char*)data.mem)[data.len - 1] != '\0') + { + ERR("Last character is not a null character! but type is text!"); + return NULL; + } + } + + content = calloc(1, sizeof(Eina_Content)); + EINA_SAFETY_ON_NULL_RETURN_VAL(content, NULL); + content->data = eina_slice_dup(data); + content->type = eina_stringshare_add(type); + EINA_SAFETY_ON_NULL_RETURN_VAL(content->data.mem, NULL); + + _eina_content_ref(content); + return content; +} + +EAPI void +eina_content_free(Eina_Content *content) +{ + EINA_REFCOUNT_UNREF(content) + { + if (content->file) + eina_tmpstr_del(content->file); + free(content->data.mem); + free(content); + } +} + +EAPI const char* +eina_content_as_file(Eina_Content *content) +{ + if (!content->file) + { + Eina_Tmpstr *path; + int fd = eina_file_mkstemp("prefixXXXXXX.ext", &path); + + if (fd < 0) + { + ERR("Failed to create tmp file"); + return NULL; + } + + if (write(fd, content->data.mem, content->data.len) < 0) + { + ERR("Failed to write to a file"); + eina_tmpstr_del(path); + close(fd); + return NULL; + } + + content->file = path; + close(fd); + } + return content->file; +} + +EAPI const char* +eina_content_type_get(Eina_Content *content) +{ + return content->type; +} + +EAPI const Eina_Slice +eina_content_data_get(Eina_Content *content) +{ + return eina_rw_slice_slice_get(content->data); +} + +EAPI Eina_Content* +eina_content_convert(Eina_Content *content, const char *new_type) +{ + Eina_Content_Conversion_Callback callback = _conversion_callback_fetch(content->type, new_type); + + if (!callback) + { + ERR("No suitable conversion found"); + return NULL; + } + + return callback(content, new_type); +} + +static Eina_Content* +_copy_converter(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + return eina_content_new(slice, to_type); +} + +static Eina_Content* +_latin1_to_utf8_converter(Eina_Content *from, const char *to_type) +{ + Eina_Slice slice = eina_content_data_get(from); + Eina_Strbuf *out = eina_strbuf_new(); + + for (unsigned int i = 0; i < slice.len; ++i) + { + const unsigned char c = ((char*)slice.mem)[i]; + if (c < 128) + eina_strbuf_append_char(out, c); + else + { + eina_strbuf_append_char(out, 0xc0 | c >> 6); + eina_strbuf_append_char(out, 0x80 | (c & 0x3f)); + } + } + Eina_Slice new; + new.len = eina_strbuf_length_get(out); + new.mem = eina_strbuf_string_get(out); + Eina_Content *c = eina_content_new(new, to_type); + eina_strbuf_free(out); + return c; +} + +static Eina_Bool +_eina_value_type_content_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem) +{ + memset(mem, 0, sizeof(Eina_Content*)); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_flush(const Eina_Value_Type *type EINA_UNUSED, + void *mem EINA_UNUSED) +{ + Eina_Content **content = mem; + + eina_content_free(*content); + + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_copy(const Eina_Value_Type *type EINA_UNUSED, const void *src, void *dst) +{ + Eina_Content * const *srcc = src; + Eina_Content **dstc = dst; + + *dstc = *srcc; + _eina_content_ref(*dstc); + return EINA_TRUE; +} + +static int +_eina_value_type_content_compare(const Eina_Value_Type *type EINA_UNUSED, const void *a, const void *b) +{ + Eina_Content * const *ra = a; + Eina_Content * const *rb = b; + + if ((*ra)->type != (*rb)->type) + return -1; + + return eina_rw_slice_compare((*ra)->data, (*rb)->data); +} + +static Eina_Bool +_eina_value_type_content_convert_to(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert EINA_UNUSED, const void *type_mem EINA_UNUSED, void *convert_mem EINA_UNUSED) +{ + Eina_Content * const *ra = type_mem; + + if (convert == EINA_VALUE_TYPE_STRINGSHARE || + convert == EINA_VALUE_TYPE_STRING) + { + const char *type = eina_content_type_get(*ra); + if (eina_streq(type, "text/plain;charset=utf-8")) + { + Eina_Slice data = eina_content_data_get(*ra); + return eina_value_type_pset(convert, convert_mem, &data.mem); + } + else + { + Eina_Iterator *iter = eina_content_possible_conversions(*ra); + const char *type; + + EINA_ITERATOR_FOREACH(iter, type) + { + if (eina_streq(type, "text/plain;charset=utf-8")) + { + Eina_Content *conv_result = eina_content_convert(*ra, type); + + Eina_Slice data = eina_content_data_get(conv_result); + Eina_Bool success = eina_value_type_pset(convert, convert_mem, &data.mem); + eina_content_free(conv_result); + return success; + } + } + //create some fallback + { + char buf[PATH_MAX]; + char *tmp = (char*) &buf; + snprintf(buf, sizeof(buf), "Content %p cannot be converted to \"text/plain;charset=utf-8\"", *ra); + return eina_value_type_pset(convert, convert_mem, &tmp); + } + } + } + return EINA_FALSE; +} + +static Eina_Bool +_eina_value_type_content_convert_from(const Eina_Value_Type *type EINA_UNUSED, const Eina_Value_Type *convert EINA_UNUSED, void *type_mem EINA_UNUSED, const void *convert_mem EINA_UNUSED) +{ + return EINA_FALSE; +} + +static Eina_Bool +_eina_value_type_content_pset(const Eina_Value_Type *type EINA_UNUSED, void *mem, const void *ptr) +{ + Eina_Content * const *srcc = ptr; + Eina_Content **dstc = mem; + + *dstc = *srcc; + _eina_content_ref(*dstc); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_vset(const Eina_Value_Type *type EINA_UNUSED, void *mem, va_list args) +{ + Eina_Content **dst = mem; + Eina_Content *content = va_arg(args, Eina_Content*); + + *dst = content; + _eina_content_ref(*dst); + return EINA_TRUE; +} + +static Eina_Bool +_eina_value_type_content_pget(const Eina_Value_Type *type EINA_UNUSED, const void *mem, void *ptr) +{ + Eina_Content * const *src = mem; + Eina_Content **dst = ptr; + + *dst = *src; + _eina_content_ref(*dst); + return EINA_TRUE; +} + +EAPI const Eina_Value_Type _EINA_VALUE_TYPE_CONTENT ={ + EINA_VALUE_TYPE_VERSION, + sizeof(Eina_Content*), + "Eina_Abstract_Content", + _eina_value_type_content_setup, + _eina_value_type_content_flush, + _eina_value_type_content_copy, + _eina_value_type_content_compare, + _eina_value_type_content_convert_to, + _eina_value_type_content_convert_from, + _eina_value_type_content_vset, + _eina_value_type_content_pset, + _eina_value_type_content_pget +}; + +static void +_free_node(void *v) +{ + Eina_Content_Conversion_Node *n; + EINA_LIST_FREE(v, n) + { + eina_stringshare_del(n->to); + free(n); + } +} + +Eina_Bool +eina_abstract_content_init(void) +{ + _eina_abstract_content_log_domain = eina_log_domain_register("eina_abstract_content", "white"); + conversion_callbacks = eina_hash_stringshared_new(_free_node); + + EINA_VALUE_TYPE_CONTENT = &_EINA_VALUE_TYPE_CONTENT; + + // text/plain is assumed to be charset "US-ASCII" + + eina_content_converter_conversion_register("text/plain", "text/plain;charset=utf-8", _copy_converter); + eina_content_converter_conversion_register("text/plain", "text/plain;charset=iso-8859-1", _copy_converter); + eina_content_converter_conversion_register("text/plain;charset=iso-8859-1", "text/plain;charset=utf-8", _latin1_to_utf8_converter); + eina_content_converter_conversion_register("text/plain;charset=iso-8859-1", "text/plain", _copy_converter); + + return EINA_TRUE; +} + +Eina_Bool +eina_abstract_content_shutdown(void) +{ + eina_hash_free(conversion_callbacks); + + return EINA_TRUE; +} + +Eina_Value* +eina_value_content_new(Eina_Content *content) +{ + Eina_Value *v = eina_value_new(EINA_VALUE_TYPE_CONTENT); + + eina_value_pset(v, &content); + return v; +} + + +Eina_Value +eina_value_content_init(Eina_Content *content) +{ + Eina_Value v; + + eina_value_setup(&v, EINA_VALUE_TYPE_CONTENT); + eina_value_pset(&v, &content); + + return v; +} + + +Eina_Content* +eina_value_to_content(const Eina_Value *value) +{ + EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_get(value) == EINA_VALUE_TYPE_CONTENT, NULL); + Eina_Content *result = calloc(1, sizeof(Eina_Content)); + eina_value_pget(value, &result); + return result; +} diff --git a/src/lib/eina/eina_abstract_content.h b/src/lib/eina/eina_abstract_content.h new file mode 100644 index 0000000000..1436543f4e --- /dev/null +++ b/src/lib/eina/eina_abstract_content.h @@ -0,0 +1,154 @@ +#ifndef EINA_ABSTRACT_CONTENT_H +#define EINA_ABSTRACT_CONTENT_H + + +/** + * @typedef Eina_Content + * Defines a abstract content segment + * + * Each Abstract content contains out of a Eina_Slice of memory. And a type. + * The type are IANA meme types. + * + * @note if the type is a text-style type, the last byte of the slice must be \0 + * + * @since 1.24 + */ +typedef struct _Eina_Content Eina_Content; + +/** + * @typedef Eina_Content_Convertion_Callback + * + * Callback called when convertion from one type to another type is requested. + * The from and to type is specified when the callback is registered. + * The to type is also passed in the callback here. + * The type of the from pointer does not need to be checked. + */ +typedef Eina_Content* (*Eina_Content_Conversion_Callback)(Eina_Content *from, const char *to_type); + +/** + * Get the path to a file, containing the slice memory as content. + * + * @param[in] content The content that will be in the file. + * + * @return The path to the file. Do not free this. + * + */ +EAPI const char* eina_content_as_file(Eina_Content *content); + +/** + * Convert the content of the object to another type. + * + * In case the convertion cannot be performaned, NULL is returned. + * + * @param[in] content The content to convert. + * @param[in] new_type The new type the returned content will have. + * + * @return A new content object. The caller of this function is owning this. + */ +EAPI Eina_Content* eina_content_convert(Eina_Content *content, const char *new_type); + +/** + * Get the type of the passed content. + * + * @param[in] content The content to fetch the type from. + * + * @return The type of this content. Do no free this. + */ +EAPI const char* eina_content_type_get(Eina_Content *content); + +/** + * Get the type of the passed content. + * + * @param[in] content The content to fetch the type from. + * + * @return The path to the file. Do not free this. + */ +EAPI const Eina_Slice eina_content_data_get(Eina_Content *content); + +/** + * Create a new content object, with the slice of data with a specific type. + * + * @param[in] data A slice of memory, the memory is duplicated. + * @param[in] type The type of memory. + * + * @return The new content object. The caller owns this object. + */ +EAPI Eina_Content* eina_content_new(Eina_Slice data, const char *type); + +/** + * Free the content object. + * + * @param[in] content The content to free. + */ +EAPI void eina_content_free(Eina_Content *content); + +/** + * Register a new conversion callback. + * + * @param[in] from The tyoe you convert from. + * @param[in] in The type you convert to. + * + * @return True on success false otherwise. + */ +EAPI Eina_Bool eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback convertion); + +/** + * Check if a specific convertion can be performanced. + * + * A convertion can only be performed if a callback is registered. + * + * @param[in] from The type you convert from. + * @param[in] in The type you convert to. + * + * @return True if it can be performed, false if not. + */ +EAPI Eina_Bool eina_content_converter_convert_can(const char *from, const char *to); + +/** + * Returns a iterator that can be used to find all the possible types that can be converted to. + * + * @param[in] form The type you convert from + * + * @return A Iterator, containing strings, free this via eina_iterator_free. + */ +EAPI Eina_Iterator* eina_content_converter_possible_conversions(const char *from); + +EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT; + +/** + * Convert the Eina_Content object to a Eina_Value. + * + * @param[in] content The Eina_Content struct that will be converted to a Eina_Value + * + * @return A Eina_Value that is allocated, you need to free it. + */ +EAPI Eina_Value* eina_value_content_new(Eina_Content *content); + +/** + * Convert the Eina_Content object to a Eina_Value. + * + * @param[in] content The Eina_Content struct that will be converted to a Eina_Value + * + * @return A Eina_Value with type EINA_VALUE_TYPE_CONTENT + */ +EAPI Eina_Value eina_value_content_init(Eina_Content *content); + +/** + * Get the content from the Eina_Value + * + * If the value is not of the type EINA_VALUE_TYPE_CONTENT, NULL will be returned and a error will be printed. + * + * @param[in] value The value to get the content from + * + * @return A allocated Eina_Content, you need to free it. + */ +EAPI Eina_Content* eina_value_to_content(const Eina_Value *value); + + +static inline Eina_Iterator* +eina_content_possible_conversions(Eina_Content *content) +{ + return eina_content_converter_possible_conversions(eina_content_type_get(content)); +} + +#endif diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c index b8856474d3..47dd80a898 100644 --- a/src/lib/eina/eina_main.c +++ b/src/lib/eina/eina_main.c @@ -154,6 +154,7 @@ extern Eina_Lock _sysmon_lock; S(slstr); S(promise); S(vpath); + S(abstract_content); #undef S struct eina_desc_setup @@ -202,6 +203,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = { S(safepointer), S(slstr), S(promise), + S(abstract_content) #undef S }; static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / diff --git a/src/lib/eina/eina_slice.h b/src/lib/eina/eina_slice.h index a354eaa566..a597fe281e 100644 --- a/src/lib/eina/eina_slice.h +++ b/src/lib/eina/eina_slice.h @@ -464,6 +464,30 @@ static inline char *eina_rw_slice_strdup(const Eina_Rw_Slice rw_slice); #else #define EINA_SLICE_STR(str) {.len = strlen((str)), .mem = (str)} #endif +/** + * @def EINA_SLICE_STR_FULL(str) + * + * Same as EINA_SLICE_STR_FULL, but it also contains the \0 element of the string + * + * @param[in] str The string to create the slice from. + * @return The initialized slice object. + * + * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice. + * + * @code + * Eina_Slice ro_slice = EINA_SLICE_STR_FULL("hello world"); + * @endcode + * + * @see EINA_SLICE_STR_FULL() for specific version using literals. + * + * @since 1.24 + */ +#ifdef __cplusplus +#define EINA_SLICE_STR_FULL(str) {strlen((str)) + 1, (str)} +#else +#define EINA_SLICE_STR_FULL(str) {.len = strlen((str)) + 1, .mem = (str)} +#endif + /** * @def EINA_SLICE_STR_FMT diff --git a/src/lib/eina/meson.build b/src/lib/eina/meson.build index 97e1669c4f..d3d30fcf43 100644 --- a/src/lib/eina/meson.build +++ b/src/lib/eina/meson.build @@ -107,6 +107,7 @@ public_sub_headers = [ 'eina_freeq.h', 'eina_slstr.h', 'eina_vpath.h', +'eina_abstract_content.h' ] public_headers = [ @@ -188,7 +189,8 @@ sources = [ 'eina_freeq.c', 'eina_slstr.c', 'eina_vpath.c', -'eina_vpath_xdg.c' +'eina_vpath_xdg.c', +'eina_abstract_content.c', ] if sys_windows == true diff --git a/src/tests/eina/eina_suite.c b/src/tests/eina/eina_suite.c index 45316bd462..01ed82a532 100644 --- a/src/tests/eina/eina_suite.c +++ b/src/tests/eina/eina_suite.c @@ -90,6 +90,7 @@ static const Efl_Test_Case etc[] = { { "slstr", eina_test_slstr }, { "Vpath", eina_test_vpath }, { "debug", eina_test_debug }, + { "Abstract Content", eina_test_abstract_content }, { NULL, NULL } }; diff --git a/src/tests/eina/eina_suite.h b/src/tests/eina/eina_suite.h index 102de63193..84d6e60516 100644 --- a/src/tests/eina/eina_suite.h +++ b/src/tests/eina/eina_suite.h @@ -78,5 +78,6 @@ void eina_test_freeq(TCase *tc); void eina_test_slstr(TCase *tc); void eina_test_vpath(TCase *tc); void eina_test_debug(TCase *tc); +void eina_test_abstract_content(TCase *tc); #endif /* EINA_SUITE_H_ */ diff --git a/src/tests/eina/eina_test_abstract_content.c b/src/tests/eina/eina_test_abstract_content.c new file mode 100644 index 0000000000..d2270ddaad --- /dev/null +++ b/src/tests/eina/eina_test_abstract_content.c @@ -0,0 +1,223 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include + +#include + +#include "eina_suite.h" + +EFL_START_TEST(eina_test_content_create_destroy) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + ck_assert_int_eq(eina_content_data_get(content).len, strlen(text_str) + 1); + ck_assert_str_eq(eina_content_data_get(content).mem, text_str); + + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_as_file) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_File *f; + const char *file_path = eina_content_as_file(content); + + f = eina_file_open(file_path, EINA_FALSE); + const char *file_content = eina_file_map_all(f, EINA_FILE_POPULATE); + ck_assert_str_eq(file_content, text_str); + eina_file_close(f); + + eina_content_free(content); + + const char *file_path2 = eina_content_as_file(content); + ck_assert_str_eq(file_path, file_path2); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_none_existing) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + + EXPECT_ERROR_START; + ck_assert_ptr_eq(eina_content_convert(content, "ThisIsReallyNotHere"), NULL); + EXPECT_ERROR_END; +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_ascii_to_utf8) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=utf-8"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=utf-8"); + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_ascii_to_latin) +{ + const char *text_str = "TestAsDf"; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=iso-8859-1"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=iso-8859-1"); + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_convert_utf8_to_latin) +{ + //this means AÄÜÖß + const char text_str[] = {'A', 0xc3, 0x84, 0xc3, 0x9c, 0xc3, 0x96, 0xc3, 0x9f, 0}; + const char text_str_latin[] = {'A', 0xC4, 0xDC, 0xD6, 0xDF, 0}; + Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str_latin), "text/plain;charset=iso-8859-1"); + Eina_Content *c = eina_content_convert(content, "text/plain;charset=utf-8"); + + ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=utf-8"); + ck_assert_int_eq(sizeof(text_str), eina_content_data_get(c).len); + for (unsigned int i = 0; i < eina_content_data_get(c).len; ++i) + { + ck_assert_int_eq(text_str[i], ((char*)eina_content_data_get(c).mem)[i]); + } + ck_assert_str_eq(eina_content_data_get(c).mem, text_str); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_possible_converstions) +{ + ck_assert_int_eq(eina_content_converter_convert_can("text/plain", "text/plain;charset=utf-8"), 1); + ck_assert_int_eq(eina_content_converter_convert_can("text/plain", "ThisDoesNotExist"), 0); + ck_assert_int_eq(eina_content_converter_convert_can("ThisDoesNotExist", "text/plain;charset=utf-8"), 0); + Eina_Iterator *iterator = eina_content_converter_possible_conversions("text/plain"); + char *text; + int i = 0, j = 0; + + EINA_ITERATOR_FOREACH(iterator, text) + { + if (eina_streq(text, "text/plain;charset=utf-8")) + i ++; + if (eina_streq(text, "text/plain;charset=iso-8859-1")) + j ++; + } + ck_assert_int_eq(i, 1); + ck_assert_int_eq(j, 1); + eina_iterator_free(iterator); +} +EFL_END_TEST + +static Eina_Bool getting_called = EINA_FALSE; + +static Eina_Content* +_test_cb(Eina_Content *content EINA_UNUSED, const char *type EINA_UNUSED) +{ + getting_called = EINA_TRUE; + return eina_content_new(eina_content_data_get(content), type); +} + +EFL_START_TEST(eina_test_register_illegal) +{ + const char *test_str = "AbCdEfG"; + eina_content_converter_conversion_register("Test", "Test2", _test_cb); + EXPECT_ERROR_START; + eina_content_converter_conversion_register("Test", "Test2", _test_cb); + EXPECT_ERROR_END; + + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(test_str), "Test"); + Eina_Content *c2 = eina_content_convert(c, "Test2"); + ck_assert_ptr_ne(c2, NULL); + ck_assert_int_eq(getting_called, EINA_TRUE); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value) +{ + const char *str_a = "All"; + const char *str_b = "Out"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Content *b = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_b), "text/plain"); + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Content *d = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "Not_Text"); + Eina_Value *va = eina_value_content_new(a); + Eina_Value *vb = eina_value_content_new(b); + Eina_Value *vc = eina_value_content_new(c); + Eina_Value *vd = eina_value_content_new(d); + Eina_Value *vcopy = eina_value_new(EINA_VALUE_TYPE_CONTENT); + Eina_Content *content; + + ck_assert_int_eq(eina_value_compare(va, vc), 0); + ck_assert_int_ne(eina_value_compare(va, vb), 0); + ck_assert_int_ne(eina_value_compare(va, vd), 0); + ck_assert_int_eq(eina_value_compare(vd, vd), 0); + + ck_assert_int_eq(eina_value_copy(va, vcopy), 1); + ck_assert_int_eq(eina_value_compare(va, vcopy), 0); + + content = eina_value_to_content(vcopy); + Eina_Slice slice = eina_content_data_get(content); + ck_assert_int_eq(slice.len, strlen(str_a) + 1); + ck_assert_str_eq(slice.mem, str_a); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value_set) +{ + const char *str_a = "All"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain"); + Eina_Value *acopy = eina_value_new(EINA_VALUE_TYPE_CONTENT); + Eina_Content *content; + + eina_value_set(acopy, a); + content = eina_value_to_content(acopy); + Eina_Slice slice = eina_content_data_get(content); + ck_assert_int_eq(slice.len, strlen(str_a) + 1); + ck_assert_str_eq(slice.mem, str_a); + + ck_assert_str_eq(eina_content_type_get(content), "text/plain"); + eina_content_free(content); +} +EFL_END_TEST + +EFL_START_TEST(eina_test_content_value_convertion) +{ + const char *str_a = "All"; + const char *str_b = "Out"; + const char *str_c = "Life"; + Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain;charset=utf-8"); + Eina_Content *b = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_b), "text/plain"); + Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_c), "application/x-elementary-markup"); + Eina_Value *av = eina_value_content_new(a); + Eina_Value *bv = eina_value_content_new(b); + Eina_Value *cv = eina_value_content_new(c); + + ck_assert_str_eq(eina_value_to_string(av), str_a); + ck_assert_str_eq(eina_value_to_string(bv), str_b); + ck_assert_str_ne(eina_value_to_string(cv), str_c); +} +EFL_END_TEST + +void +eina_test_abstract_content(TCase *tc) +{ + tcase_add_test(tc, eina_test_content_create_destroy); + tcase_add_test(tc, eina_test_content_as_file); + tcase_add_test(tc, eina_test_content_convert_none_existing); + tcase_add_test(tc, eina_test_content_convert_ascii_to_utf8); + tcase_add_test(tc, eina_test_content_convert_ascii_to_latin); + tcase_add_test(tc, eina_test_content_convert_utf8_to_latin); + tcase_add_test(tc, eina_test_content_possible_converstions); + tcase_add_test(tc, eina_test_register_illegal); + tcase_add_test(tc, eina_test_content_value); + tcase_add_test(tc, eina_test_content_value_set); + tcase_add_test(tc, eina_test_content_value_convertion); +} diff --git a/src/tests/eina/meson.build b/src/tests/eina/meson.build index f755be4c2a..18c8f91ced 100644 --- a/src/tests/eina/meson.build +++ b/src/tests/eina/meson.build @@ -54,7 +54,8 @@ eina_test_src = files( 'eina_test_slice.c', 'eina_test_freeq.c', 'eina_test_slstr.c', -'eina_test_vpath.c' +'eina_test_vpath.c', +'eina_test_abstract_content.c', )