From 113d35f6da5997850c7b4a73c93373cd2dd45f03 Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Thu, 12 Jan 2012 03:00:03 +0000 Subject: [PATCH] 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 --- legacy/eina/src/include/eina_value.h | 54 ++++++ legacy/eina/src/lib/eina_value.c | 230 ++++++++++++++++++++++++ legacy/eina/src/tests/eina_test_value.c | 45 +++++ 3 files changed, 329 insertions(+) diff --git a/legacy/eina/src/include/eina_value.h b/legacy/eina/src/include/eina_value.h index e3aef99d77..64ddacbf15 100644 --- a/legacy/eina/src/include/eina_value.h +++ b/legacy/eina/src/include/eina_value.h @@ -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 diff --git a/legacy/eina/src/lib/eina_value.c b/legacy/eina/src/lib/eina_value.c index 0da6600b4a..98340b24af 100644 --- a/legacy/eina/src/lib/eina_value.c +++ b/legacy/eina/src/lib/eina_value.c @@ -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; diff --git a/legacy/eina/src/tests/eina_test_value.c b/legacy/eina/src/tests/eina_test_value.c index ab8567e2c5..e8e0c7b7f3 100644 --- a/legacy/eina/src/tests/eina_test_value.c +++ b/legacy/eina/src/tests/eina_test_value.c @@ -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); }