forked from enlightenment/efl
eina_value: add blob type.
Nice type that even supports configurable operations such as compare, free, copy and to_string. the usual is also supported: provide no ops (operations) and memory will be left untouched. nice feature to dump as string :-) SVN revision: 67109
This commit is contained in:
parent
ed2183c146
commit
113d35f6da
|
@ -243,6 +243,12 @@ EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_HASH;
|
|||
*/
|
||||
EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_TIMEVAL;
|
||||
|
||||
/**
|
||||
* @var EINA_VALUE_TYPE_BLOB
|
||||
* manages blob of bytes type, see @ref Eina_Value_Blob
|
||||
* @since 1.2
|
||||
*/
|
||||
EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_BLOB;
|
||||
|
||||
/**
|
||||
* @var EINA_ERROR_VALUE_FAILED
|
||||
|
@ -2243,6 +2249,54 @@ static inline Eina_Bool eina_value_hash_pget(const Eina_Value *value,
|
|||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup Eina_Value_Blob_Group Generic Value Blob management
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Eina_Value_Blob_Operations
|
||||
* How to manage blob. Any @c NULL callback is ignored.
|
||||
* @since 1.2
|
||||
*/
|
||||
typedef struct _Eina_Value_Blob_Operations Eina_Value_Blob_Operations;
|
||||
|
||||
/**
|
||||
* @struct _Eina_Value_Blob_Operations
|
||||
* How to manage blob. Any @c NULL callback is ignored.
|
||||
* @since 1.2
|
||||
*/
|
||||
struct _Eina_Value_Blob_Operations
|
||||
{
|
||||
#define EINA_VALUE_BLOB_OPERATIONS_VERSION (1)
|
||||
unsigned int version; /**< must be EINA_VALUE_BLOB_OPERATIONS_VERSION */
|
||||
void (*free)(const Eina_Value_Blob_Operations *ops, void *memory, size_t size);
|
||||
void *(*copy)(const Eina_Value_Blob_Operations *ops, const void *memory, size_t size);
|
||||
int (*compare)(const Eina_Value_Blob_Operations *ops, const void *data1, size_t size_data1, const void *data2, size_t size_data2);
|
||||
char *(*to_string)(const Eina_Value_Blob_Operations *ops, const void *memory, size_t size);
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef Eina_Value_Blob
|
||||
* @since 1.2
|
||||
*/
|
||||
typedef struct _Eina_Value_Blob Eina_Value_Blob;
|
||||
|
||||
/**
|
||||
* @struct _Eina_Value_Blob
|
||||
* @since 1.2
|
||||
*/
|
||||
struct _Eina_Value_Blob
|
||||
{
|
||||
const Eina_Value_Blob_Operations *ops; /**< if @c NULL, nothing is freed, copy will just copy the memory pointer, not its value. */
|
||||
const void *memory;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup Eina_Value_Type_Group Generic Value Type management
|
||||
|
|
|
@ -3529,6 +3529,234 @@ static const Eina_Value_Type _EINA_VALUE_TYPE_TIMEVAL = {
|
|||
_eina_value_type_timeval_pget
|
||||
};
|
||||
|
||||
static Eina_Bool
|
||||
_eina_value_type_blob_setup(const Eina_Value_Type *type __UNUSED__, void *mem)
|
||||
{
|
||||
memset(mem, 0, sizeof(Eina_Value_Blob));
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static inline const Eina_Value_Blob_Operations *
|
||||
_eina_value_type_blob_ops_get(const Eina_Value_Blob *blob)
|
||||
{
|
||||
if (!blob) return NULL;
|
||||
if (!blob->ops) return NULL;
|
||||
EINA_SAFETY_ON_FALSE_RETURN_VAL
|
||||
(blob->ops->version == EINA_VALUE_BLOB_OPERATIONS_VERSION, NULL);
|
||||
return blob->ops;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_eina_value_type_blob_flush(const Eina_Value_Type *type __UNUSED__, void *mem)
|
||||
{
|
||||
const Eina_Value_Blob_Operations *ops = _eina_value_type_blob_ops_get(mem);
|
||||
Eina_Value_Blob *tmem = mem;
|
||||
if ((ops) && (ops->free))
|
||||
ops->free(ops, (void *)tmem->memory, tmem->size);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_eina_value_type_blob_copy(const Eina_Value_Type *type __UNUSED__, const void *src, void *dst)
|
||||
{
|
||||
const Eina_Value_Blob_Operations *ops = _eina_value_type_blob_ops_get(src);
|
||||
const Eina_Value_Blob *s = src;
|
||||
Eina_Value_Blob *d = dst;
|
||||
|
||||
*d = *s;
|
||||
|
||||
if ((ops) && (ops->copy))
|
||||
{
|
||||
d->memory = ops->copy(ops, s->memory, s->size);
|
||||
if ((d->memory == NULL) && (s->size > 0))
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
_eina_value_type_blob_compare(const Eina_Value_Type *type __UNUSED__, const void *a, const void *b)
|
||||
{
|
||||
const Eina_Value_Blob_Operations *ops = _eina_value_type_blob_ops_get(a);
|
||||
const Eina_Value_Blob *ta = a, *tb = b;
|
||||
size_t minsize;
|
||||
if (ta->ops != tb->ops)
|
||||
{
|
||||
eina_error_set(EINA_ERROR_VALUE_FAILED);
|
||||
return -1;
|
||||
}
|
||||
if ((ops) && (ops->compare))
|
||||
return ops->compare(ops, ta->memory, ta->size, tb->memory, tb->size);
|
||||
|
||||
if (ta->size < tb->size)
|
||||
minsize = ta->size;
|
||||
else
|
||||
minsize = tb->size;
|
||||
|
||||
return memcmp(ta->memory, tb->memory, minsize);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_eina_value_type_blob_convert_to(const Eina_Value_Type *type __UNUSED__, const Eina_Value_Type *convert, const void *type_mem, void *convert_mem)
|
||||
{
|
||||
const Eina_Value_Blob *tmem = type_mem;
|
||||
|
||||
eina_error_set(0);
|
||||
if (convert == EINA_VALUE_TYPE_STRINGSHARE ||
|
||||
convert == EINA_VALUE_TYPE_STRING)
|
||||
{
|
||||
const Eina_Value_Blob_Operations *ops;
|
||||
Eina_Strbuf *str;
|
||||
const char *other_mem;
|
||||
Eina_Bool ret = EINA_FALSE, first = EINA_TRUE;
|
||||
const unsigned char *ptr, *ptr_end;
|
||||
|
||||
ops = _eina_value_type_blob_ops_get(tmem);
|
||||
if ((ops) && (ops->to_string))
|
||||
{
|
||||
char *x = ops->to_string(ops, tmem->memory, tmem->size);
|
||||
if (x)
|
||||
{
|
||||
ret = eina_value_type_pset(convert, convert_mem, &x);
|
||||
free(x);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
str = eina_strbuf_new();
|
||||
if (!str)
|
||||
return EINA_FALSE;
|
||||
|
||||
if (!eina_strbuf_append_printf(str, "BLOB(%u, [", tmem->size))
|
||||
goto error;
|
||||
|
||||
ptr = tmem->memory;
|
||||
ptr_end = ptr + tmem->size;
|
||||
for (; ptr < ptr_end; ptr++)
|
||||
{
|
||||
if (first)
|
||||
{
|
||||
first = EINA_FALSE;
|
||||
if (!eina_strbuf_append_printf(str, "%02hhx", *ptr))
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!eina_strbuf_append_printf(str, " %02hhx", *ptr))
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
if (!eina_strbuf_append(str, "])"))
|
||||
goto error;
|
||||
|
||||
other_mem = eina_strbuf_string_get(str);
|
||||
ret = eina_value_type_pset(convert, convert_mem, &other_mem);
|
||||
|
||||
error:
|
||||
eina_strbuf_free(str);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
{
|
||||
eina_error_set(EINA_ERROR_VALUE_FAILED);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_eina_value_type_blob_converted_ops_free(const Eina_Value_Blob_Operations *ops __UNUSED__, void *memory, size_t size __UNUSED__)
|
||||
{
|
||||
free(memory);
|
||||
}
|
||||
|
||||
static void *
|
||||
_eina_value_type_blob_converted_ops_copy(const Eina_Value_Blob_Operations *ops __UNUSED__, const void *memory, size_t size)
|
||||
{
|
||||
void *ret = malloc(size);
|
||||
if (!ret)
|
||||
{
|
||||
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ret, memory, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const Eina_Value_Blob_Operations _eina_value_type_blob_converted_ops = {
|
||||
EINA_VALUE_BLOB_OPERATIONS_VERSION,
|
||||
_eina_value_type_blob_converted_ops_free,
|
||||
_eina_value_type_blob_converted_ops_copy,
|
||||
NULL, /* default compare */
|
||||
NULL, /* default to_string */
|
||||
};
|
||||
|
||||
static Eina_Bool
|
||||
_eina_value_type_blob_convert_from(const Eina_Value_Type *type, const Eina_Value_Type *convert, void *type_mem, const void *convert_mem)
|
||||
{
|
||||
Eina_Value_Blob desc;
|
||||
char *buf;
|
||||
|
||||
buf = malloc(convert->value_size);
|
||||
if (!buf)
|
||||
{
|
||||
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
if (!eina_value_type_pget(convert, convert_mem, buf))
|
||||
return EINA_FALSE;
|
||||
|
||||
desc.ops = &_eina_value_type_blob_converted_ops;
|
||||
desc.memory = buf;
|
||||
desc.size = convert->value_size;
|
||||
return eina_value_type_pset(type, type_mem, &desc);
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_eina_value_type_blob_pset(const Eina_Value_Type *type __UNUSED__, void *mem, const void *ptr)
|
||||
{
|
||||
const Eina_Value_Blob_Operations *ops = _eina_value_type_blob_ops_get(mem);
|
||||
Eina_Value_Blob *tmem = mem;
|
||||
const Eina_Value_Blob *desc = ptr;
|
||||
|
||||
if ((ops) && (ops->free))
|
||||
ops->free(ops, (void *)tmem->memory, tmem->size);
|
||||
|
||||
*tmem = *desc;
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_eina_value_type_blob_vset(const Eina_Value_Type *type, void *mem, va_list args)
|
||||
{
|
||||
const Eina_Value_Blob desc = va_arg(args, Eina_Value_Blob);
|
||||
_eina_value_type_blob_pset(type, mem, &desc);
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
_eina_value_type_blob_pget(const Eina_Value_Type *type __UNUSED__, const void *mem, void *ptr)
|
||||
{
|
||||
memcpy(ptr, mem, sizeof(Eina_Value_Blob));
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
static const Eina_Value_Type _EINA_VALUE_TYPE_BLOB = {
|
||||
EINA_VALUE_TYPE_VERSION,
|
||||
sizeof(Eina_Value_Blob),
|
||||
"Eina_Value_Blob",
|
||||
_eina_value_type_blob_setup,
|
||||
_eina_value_type_blob_flush,
|
||||
_eina_value_type_blob_copy,
|
||||
_eina_value_type_blob_compare,
|
||||
_eina_value_type_blob_convert_to,
|
||||
_eina_value_type_blob_convert_from,
|
||||
_eina_value_type_blob_vset,
|
||||
_eina_value_type_blob_pset,
|
||||
_eina_value_type_blob_pget
|
||||
};
|
||||
|
||||
/* keep all basic types inlined in an array so we can compare if it's
|
||||
* a basic type using pointer arithmetic.
|
||||
*
|
||||
|
@ -3790,6 +4018,7 @@ eina_value_init(void)
|
|||
EINA_VALUE_TYPE_LIST = &_EINA_VALUE_TYPE_LIST;
|
||||
EINA_VALUE_TYPE_HASH = &_EINA_VALUE_TYPE_HASH;
|
||||
EINA_VALUE_TYPE_TIMEVAL = &_EINA_VALUE_TYPE_TIMEVAL;
|
||||
EINA_VALUE_TYPE_BLOB = &_EINA_VALUE_TYPE_BLOB;
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
@ -3842,6 +4071,7 @@ EAPI const Eina_Value_Type *EINA_VALUE_TYPE_ARRAY = NULL;
|
|||
EAPI const Eina_Value_Type *EINA_VALUE_TYPE_LIST = NULL;
|
||||
EAPI const Eina_Value_Type *EINA_VALUE_TYPE_HASH = NULL;
|
||||
EAPI const Eina_Value_Type *EINA_VALUE_TYPE_TIMEVAL = NULL;
|
||||
EAPI const Eina_Value_Type *EINA_VALUE_TYPE_BLOB = NULL;
|
||||
|
||||
EAPI Eina_Error EINA_ERROR_VALUE_FAILED = 0;
|
||||
|
||||
|
|
|
@ -1376,6 +1376,50 @@ START_TEST(eina_value_test_timeval)
|
|||
fail_unless(eina_value_set(&other, itv));
|
||||
fail_unless(eina_value_compare(value, &other) == 0);
|
||||
|
||||
eina_value_flush(&other);
|
||||
|
||||
|
||||
eina_value_free(value);
|
||||
eina_shutdown();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
|
||||
START_TEST(eina_value_test_blob)
|
||||
{
|
||||
Eina_Value *value, other;
|
||||
Eina_Value_Blob in, out;
|
||||
unsigned char blob[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
|
||||
int i = 0x11223344;
|
||||
char *str;
|
||||
|
||||
eina_init();
|
||||
|
||||
value = eina_value_new(EINA_VALUE_TYPE_BLOB);
|
||||
fail_unless(value != NULL);
|
||||
|
||||
in.ops = NULL;
|
||||
in.memory = blob;
|
||||
in.size = sizeof(blob);
|
||||
fail_unless(eina_value_set(value, in));
|
||||
fail_unless(eina_value_get(value, &out));
|
||||
fail_unless(out.memory == blob);
|
||||
fail_unless(out.size == sizeof(blob));
|
||||
fail_unless(memcmp(&in, &out, sizeof(Eina_Value_Blob)) == 0);
|
||||
|
||||
str = eina_value_to_string(value);
|
||||
fail_unless(str != NULL);
|
||||
fail_unless(strcmp(str, "BLOB(10, [01 02 03 04 05 06 07 08 09 0a])") == 0);
|
||||
free(str);
|
||||
|
||||
fail_unless(eina_value_setup(&other, EINA_VALUE_TYPE_INT));
|
||||
fail_unless(eina_value_set(&other, i));
|
||||
fail_unless(eina_value_convert(&other, value));
|
||||
fail_unless(eina_value_get(value, &out));
|
||||
|
||||
fail_unless(out.memory != NULL);
|
||||
fail_unless(out.size == sizeof(int));
|
||||
fail_unless(memcmp(&i, out.memory, sizeof(int)) == 0);
|
||||
|
||||
eina_value_flush(&other);
|
||||
|
||||
|
@ -1400,4 +1444,5 @@ eina_test_value(TCase *tc)
|
|||
tcase_add_test(tc, eina_value_test_list);
|
||||
tcase_add_test(tc, eina_value_test_hash);
|
||||
tcase_add_test(tc, eina_value_test_timeval);
|
||||
tcase_add_test(tc, eina_value_test_blob);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue