forked from enlightenment/efl
eina: introduce Eina_Abstract_Content
A little abstraction to have abstract data content bound to a type. Reviewed-by: Cedric BAIL <cedric.bail@free.fr> Reviewed-by: Xavi Artigas <xavierartigas@yahoo.es> Differential Revision: https://phab.enlightenment.org/D11018
This commit is contained in:
parent
f6464b0deb
commit
40a62ddf94
|
@ -272,6 +272,7 @@ extern "C" {
|
|||
#include <eina_debug.h>
|
||||
#include <eina_promise.h>
|
||||
#include <eina_vpath.h>
|
||||
#include <eina_abstract_content.h>
|
||||
|
||||
#undef EAPI
|
||||
#define EAPI
|
||||
|
|
|
@ -0,0 +1,443 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <Eina.h>
|
||||
#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;
|
||||
}
|
|
@ -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
|
|
@ -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) /
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <Eina.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -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',
|
||||
)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue