summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hollerbach <mail@marcel-hollerbach.de>2020-01-04 15:08:08 +0100
committerMarcel Hollerbach <mail@marcel-hollerbach.de>2020-03-04 17:26:29 +0100
commitff4cba32c3ec316eb9a748165bc0014906256f81 (patch)
tree6c1609b170cf6981bc38d8f59150448db6b0896f
parentc872940baefc5fa04a9d902c20d766dd0ffd3648 (diff)
eina: introduce Eina_Abstract_Content
A little abstraction to have abstract data content bound to a type. Differential Revision: https://phab.enlightenment.org/D11018
-rw-r--r--src/lib/eina/Eina.h1
-rw-r--r--src/lib/eina/eina_abstract_content.c443
-rw-r--r--src/lib/eina/eina_abstract_content.h154
-rw-r--r--src/lib/eina/eina_main.c2
-rw-r--r--src/lib/eina/eina_slice.h24
-rw-r--r--src/lib/eina/meson.build4
-rw-r--r--src/tests/eina/eina_suite.c1
-rw-r--r--src/tests/eina/eina_suite.h1
-rw-r--r--src/tests/eina/eina_test_abstract_content.c223
-rw-r--r--src/tests/eina/meson.build3
10 files changed, 854 insertions, 2 deletions
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" {
272#include <eina_debug.h> 272#include <eina_debug.h>
273#include <eina_promise.h> 273#include <eina_promise.h>
274#include <eina_vpath.h> 274#include <eina_vpath.h>
275#include <eina_abstract_content.h>
275 276
276#undef EAPI 277#undef EAPI
277#define EAPI 278#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 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <Eina.h>
6#include "eina_abstract_content.h"
7
8struct _Eina_Content
9{
10 Eina_Rw_Slice data;
11 const char *type;
12 const char *file;
13 EINA_REFCOUNT;
14};
15EAPI const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT;
16
17static int _eina_abstract_content_log_domain = -1;
18
19#ifdef ERR
20#undef ERR
21#endif
22#define ERR(...) EINA_LOG_DOM_ERR(_eina_abstract_content_log_domain, __VA_ARGS__)
23
24#ifdef DBG
25#undef DBG
26#endif
27#define DBG(...) EINA_LOG_DOM_DBG(_eina_abstract_content_log_domain, __VA_ARGS__)
28
29static Eina_Hash *conversion_callbacks;
30
31typedef struct {
32 const char *to;
33 Eina_Content_Conversion_Callback callback;
34} Eina_Content_Conversion_Node;
35
36static void
37_eina_content_ref(Eina_Content *content)
38{
39 EINA_REFCOUNT_REF(content);
40}
41
42EAPI Eina_Bool
43eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback conversion)
44{
45 Eina_Content_Conversion_Node *node = calloc(1, sizeof(Eina_Content_Conversion_Node));
46
47 Eina_Stringshare *shared_from = eina_stringshare_add(from);
48
49 if (eina_content_converter_convert_can(from, to))
50 {
51 ERR("Convertion from %s to %s is already possible", from, to);
52 return EINA_FALSE;
53 }
54
55 node->to = eina_stringshare_add(to);
56 node->callback = conversion;
57
58 eina_hash_list_append(conversion_callbacks, shared_from, node);
59
60 return EINA_TRUE;
61}
62
63static inline Eina_List*
64_conversion_callback_fetch_possible(const char *from)
65{
66 Eina_Stringshare *shared_from = eina_stringshare_add(from);
67 Eina_List *res = eina_hash_find(conversion_callbacks, shared_from);
68 eina_stringshare_del(shared_from);
69 return res;
70}
71
72static inline Eina_Content_Conversion_Callback
73_conversion_callback_fetch(const char *from, const char *to)
74{
75 Eina_List *possibilities = _conversion_callback_fetch_possible(from);
76 Eina_Content_Conversion_Node *n;
77 Eina_Content_Conversion_Callback result = NULL;
78 Eina_List *l;
79 Eina_Stringshare *shared_to = eina_stringshare_add(to);
80
81 EINA_LIST_FOREACH(possibilities, l, n)
82 {
83 if (n->to == shared_to)
84 {
85 result = n->callback;
86 goto end;
87 }
88 }
89end:
90 eina_stringshare_del(shared_to);
91 return result;
92}
93
94EAPI Eina_Bool
95eina_content_converter_convert_can(const char *from, const char *to)
96{
97 return !!_conversion_callback_fetch(from, to);
98}
99
100static const void*
101_process_cb(const void *container EINA_UNUSED, void *data, void *fdata EINA_UNUSED)
102{
103 Eina_Content_Conversion_Node *n = data;
104
105 return n->to;
106 }
107
108EAPI Eina_Iterator*
109eina_content_converter_possible_conversions(const char *from)
110{
111 Eina_List *possibilities = _conversion_callback_fetch_possible(from);
112
113 return eina_iterator_processed_new(eina_list_iterator_new(possibilities) , EINA_PROCESS_CB(_process_cb), NULL, possibilities);
114}
115
116EAPI Eina_Content*
117eina_content_new(Eina_Slice data, const char *type)
118{
119 Eina_Content *content;
120
121 if (!strncmp(type, "text", strlen("text")))
122 {
123 //last char in the mem must be \0
124 if (((char*)data.mem)[data.len - 1] != '\0')
125 {
126 ERR("Last character is not a null character! but type is text!");
127 return NULL;
128 }
129 }
130
131 content = calloc(1, sizeof(Eina_Content));
132 EINA_SAFETY_ON_NULL_RETURN_VAL(content, NULL);
133 content->data = eina_slice_dup(data);
134 content->type = eina_stringshare_add(type);
135 EINA_SAFETY_ON_NULL_RETURN_VAL(content->data.mem, NULL);
136
137 _eina_content_ref(content);
138 return content;
139}
140
141EAPI void
142eina_content_free(Eina_Content *content)
143{
144 EINA_REFCOUNT_UNREF(content)
145 {
146 if (content->file)
147 eina_tmpstr_del(content->file);
148 free(content->data.mem);
149 free(content);
150 }
151}
152
153EAPI const char*
154eina_content_as_file(Eina_Content *content)
155{
156 if (!content->file)
157 {
158 Eina_Tmpstr *path;
159 int fd = eina_file_mkstemp("prefixXXXXXX.ext", &path);
160
161 if (fd < 0)
162 {
163 ERR("Failed to create tmp file");
164 return NULL;
165 }
166
167 if (write(fd, content->data.mem, content->data.len) < 0)
168 {
169 ERR("Failed to write to a file");
170 eina_tmpstr_del(path);
171 close(fd);
172 return NULL;
173 }
174
175 content->file = path;
176 close(fd);
177 }
178 return content->file;
179}
180
181EAPI const char*
182eina_content_type_get(Eina_Content *content)
183{
184 return content->type;
185}
186
187EAPI const Eina_Slice
188eina_content_data_get(Eina_Content *content)
189{
190 return eina_rw_slice_slice_get(content->data);
191}
192
193EAPI Eina_Content*
194eina_content_convert(Eina_Content *content, const char *new_type)
195{
196 Eina_Content_Conversion_Callback callback = _conversion_callback_fetch(content->type, new_type);
197
198 if (!callback)
199 {
200 ERR("No suitable conversion found");
201 return NULL;
202 }
203
204 return callback(content, new_type);
205}
206
207static Eina_Content*
208_copy_converter(Eina_Content *from, const char *to_type)
209{
210 Eina_Slice slice = eina_content_data_get(from);
211 return eina_content_new(slice, to_type);
212}
213
214static Eina_Content*
215_latin1_to_utf8_converter(Eina_Content *from, const char *to_type)
216{
217 Eina_Slice slice = eina_content_data_get(from);
218 Eina_Strbuf *out = eina_strbuf_new();
219
220 for (unsigned int i = 0; i < slice.len; ++i)
221 {
222 const unsigned char c = ((char*)slice.mem)[i];
223 if (c < 128)
224 eina_strbuf_append_char(out, c);
225 else
226 {
227 eina_strbuf_append_char(out, 0xc0 | c >> 6);
228 eina_strbuf_append_char(out, 0x80 | (c & 0x3f));
229 }
230 }
231 Eina_Slice new;
232 new.len = eina_strbuf_length_get(out);
233 new.mem = eina_strbuf_string_get(out);
234 Eina_Content *c = eina_content_new(new, to_type);
235 eina_strbuf_free(out);
236 return c;
237}
238
239static Eina_Bool
240_eina_value_type_content_setup(const Eina_Value_Type *type EINA_UNUSED, void *mem)
241{
242 memset(mem, 0, sizeof(Eina_Content*));
243 return EINA_TRUE;
244}
245
246static Eina_Bool
247_eina_value_type_content_flush(const Eina_Value_Type *type EINA_UNUSED,
248 void *mem EINA_UNUSED)
249{
250 Eina_Content **content = mem;
251
252 eina_content_free(*content);
253
254 return EINA_TRUE;
255}
256
257static Eina_Bool
258_eina_value_type_content_copy(const Eina_Value_Type *type EINA_UNUSED, const void *src, void *dst)
259{
260 Eina_Content * const *srcc = src;
261 Eina_Content **dstc = dst;
262
263 *dstc = *srcc;
264 _eina_content_ref(*dstc);
265 return EINA_TRUE;
266}
267
268static int
269_eina_value_type_content_compare(const Eina_Value_Type *type EINA_UNUSED, const void *a, const void *b)
270{
271 Eina_Content * const *ra = a;
272 Eina_Content * const *rb = b;
273
274 if ((*ra)->type != (*rb)->type)
275 return -1;
276
277 return eina_rw_slice_compare((*ra)->data, (*rb)->data);
278}
279
280static Eina_Bool
281_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)
282{
283 Eina_Content * const *ra = type_mem;
284
285 if (convert == EINA_VALUE_TYPE_STRINGSHARE ||
286 convert == EINA_VALUE_TYPE_STRING)
287 {
288 const char *type = eina_content_type_get(*ra);
289 if (eina_streq(type, "text/plain;charset=utf-8"))
290 {
291 Eina_Slice data = eina_content_data_get(*ra);
292 return eina_value_type_pset(convert, convert_mem, &data.mem);
293 }
294 else
295 {
296 Eina_Iterator *iter = eina_content_possible_conversions(*ra);
297 const char *type;
298
299 EINA_ITERATOR_FOREACH(iter, type)
300 {
301 if (eina_streq(type, "text/plain;charset=utf-8"))
302 {
303 Eina_Content *conv_result = eina_content_convert(*ra, type);
304
305 Eina_Slice data = eina_content_data_get(conv_result);
306 Eina_Bool success = eina_value_type_pset(convert, convert_mem, &data.mem);
307 eina_content_free(conv_result);
308 return success;
309 }
310 }
311 //create some fallback
312 {
313 char buf[PATH_MAX];
314 char *tmp = (char*) &buf;
315 snprintf(buf, sizeof(buf), "Content %p cannot be converted to \"text/plain;charset=utf-8\"", *ra);
316 return eina_value_type_pset(convert, convert_mem, &tmp);
317 }
318 }
319 }
320 return EINA_FALSE;
321}
322
323static Eina_Bool
324_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)
325{
326 return EINA_FALSE;
327}
328
329static Eina_Bool
330_eina_value_type_content_pset(const Eina_Value_Type *type EINA_UNUSED, void *mem, const void *ptr)
331{
332 Eina_Content * const *srcc = ptr;
333 Eina_Content **dstc = mem;
334
335 *dstc = *srcc;
336 _eina_content_ref(*dstc);
337 return EINA_TRUE;
338}
339
340static Eina_Bool
341_eina_value_type_content_vset(const Eina_Value_Type *type EINA_UNUSED, void *mem, va_list args)
342{
343 Eina_Content **dst = mem;
344 Eina_Content *content = va_arg(args, Eina_Content*);
345
346 *dst = content;
347 _eina_content_ref(*dst);
348 return EINA_TRUE;
349}
350
351static Eina_Bool
352_eina_value_type_content_pget(const Eina_Value_Type *type EINA_UNUSED, const void *mem, void *ptr)
353{
354 Eina_Content * const *src = mem;
355 Eina_Content **dst = ptr;
356
357 *dst = *src;
358 _eina_content_ref(*dst);
359 return EINA_TRUE;
360}
361
362EAPI const Eina_Value_Type _EINA_VALUE_TYPE_CONTENT ={
363 EINA_VALUE_TYPE_VERSION,
364 sizeof(Eina_Content*),
365 "Eina_Abstract_Content",
366 _eina_value_type_content_setup,
367 _eina_value_type_content_flush,
368 _eina_value_type_content_copy,
369 _eina_value_type_content_compare,
370 _eina_value_type_content_convert_to,
371 _eina_value_type_content_convert_from,
372 _eina_value_type_content_vset,
373 _eina_value_type_content_pset,
374 _eina_value_type_content_pget
375};
376
377static void
378_free_node(void *v)
379{
380 Eina_Content_Conversion_Node *n;
381 EINA_LIST_FREE(v, n)
382 {
383 eina_stringshare_del(n->to);
384 free(n);
385 }
386}
387
388Eina_Bool
389eina_abstract_content_init(void)
390{
391 _eina_abstract_content_log_domain = eina_log_domain_register("eina_abstract_content", "white");
392 conversion_callbacks = eina_hash_stringshared_new(_free_node);
393
394 EINA_VALUE_TYPE_CONTENT = &_EINA_VALUE_TYPE_CONTENT;
395
396 // text/plain is assumed to be charset "US-ASCII"
397
398 eina_content_converter_conversion_register("text/plain", "text/plain;charset=utf-8", _copy_converter);
399 eina_content_converter_conversion_register("text/plain", "text/plain;charset=iso-8859-1", _copy_converter);
400 eina_content_converter_conversion_register("text/plain;charset=iso-8859-1", "text/plain;charset=utf-8", _latin1_to_utf8_converter);
401 eina_content_converter_conversion_register("text/plain;charset=iso-8859-1", "text/plain", _copy_converter);
402
403 return EINA_TRUE;
404}
405
406Eina_Bool
407eina_abstract_content_shutdown(void)
408{
409 eina_hash_free(conversion_callbacks);
410
411 return EINA_TRUE;
412}
413
414Eina_Value*
415eina_value_content_new(Eina_Content *content)
416{
417 Eina_Value *v = eina_value_new(EINA_VALUE_TYPE_CONTENT);
418
419 eina_value_pset(v, &content);
420 return v;
421}
422
423
424Eina_Value
425eina_value_content_init(Eina_Content *content)
426{
427 Eina_Value v;
428
429 eina_value_setup(&v, EINA_VALUE_TYPE_CONTENT);
430 eina_value_pset(&v, &content);
431
432 return v;
433}
434
435
436Eina_Content*
437eina_value_to_content(const Eina_Value *value)
438{
439 EINA_SAFETY_ON_FALSE_RETURN_VAL(eina_value_type_get(value) == EINA_VALUE_TYPE_CONTENT, NULL);
440 Eina_Content *result = calloc(1, sizeof(Eina_Content));
441 eina_value_pget(value, &result);
442 return result;
443}
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 @@
1#ifndef EINA_ABSTRACT_CONTENT_H
2#define EINA_ABSTRACT_CONTENT_H
3
4
5/**
6 * @typedef Eina_Content
7 * Defines a abstract content segment
8 *
9 * Each Abstract content contains out of a Eina_Slice of memory. And a type.
10 * The type are IANA meme types.
11 *
12 * @note if the type is a text-style type, the last byte of the slice must be \0
13 *
14 * @since 1.24
15 */
16typedef struct _Eina_Content Eina_Content;
17
18/**
19 * @typedef Eina_Content_Convertion_Callback
20 *
21 * Callback called when convertion from one type to another type is requested.
22 * The from and to type is specified when the callback is registered.
23 * The to type is also passed in the callback here.
24 * The type of the from pointer does not need to be checked.
25 */
26typedef Eina_Content* (*Eina_Content_Conversion_Callback)(Eina_Content *from, const char *to_type);
27
28/**
29 * Get the path to a file, containing the slice memory as content.
30 *
31 * @param[in] content The content that will be in the file.
32 *
33 * @return The path to the file. Do not free this.
34 *
35 */
36EAPI const char* eina_content_as_file(Eina_Content *content);
37
38/**
39 * Convert the content of the object to another type.
40 *
41 * In case the convertion cannot be performaned, NULL is returned.
42 *
43 * @param[in] content The content to convert.
44 * @param[in] new_type The new type the returned content will have.
45 *
46 * @return A new content object. The caller of this function is owning this.
47 */
48EAPI Eina_Content* eina_content_convert(Eina_Content *content, const char *new_type);
49
50/**
51 * Get the type of the passed content.
52 *
53 * @param[in] content The content to fetch the type from.
54 *
55 * @return The type of this content. Do no free this.
56 */
57EAPI const char* eina_content_type_get(Eina_Content *content);
58
59/**
60 * Get the type of the passed content.
61 *
62 * @param[in] content The content to fetch the type from.
63 *
64 * @return The path to the file. Do not free this.
65 */
66EAPI const Eina_Slice eina_content_data_get(Eina_Content *content);
67
68/**
69 * Create a new content object, with the slice of data with a specific type.
70 *
71 * @param[in] data A slice of memory, the memory is duplicated.
72 * @param[in] type The type of memory.
73 *
74 * @return The new content object. The caller owns this object.
75 */
76EAPI Eina_Content* eina_content_new(Eina_Slice data, const char *type);
77
78/**
79 * Free the content object.
80 *
81 * @param[in] content The content to free.
82 */
83EAPI void eina_content_free(Eina_Content *content);
84
85/**
86 * Register a new conversion callback.
87 *
88 * @param[in] from The tyoe you convert from.
89 * @param[in] in The type you convert to.
90 *
91 * @return True on success false otherwise.
92 */
93EAPI Eina_Bool eina_content_converter_conversion_register(const char *from, const char *to, Eina_Content_Conversion_Callback convertion);
94
95/**
96 * Check if a specific convertion can be performanced.
97 *
98 * A convertion can only be performed if a callback is registered.
99 *
100 * @param[in] from The type you convert from.
101 * @param[in] in The type you convert to.
102 *
103 * @return True if it can be performed, false if not.
104 */
105EAPI Eina_Bool eina_content_converter_convert_can(const char *from, const char *to);
106
107/**
108 * Returns a iterator that can be used to find all the possible types that can be converted to.
109 *
110 * @param[in] form The type you convert from
111 *
112 * @return A Iterator, containing strings, free this via eina_iterator_free.
113 */
114EAPI Eina_Iterator* eina_content_converter_possible_conversions(const char *from);
115
116EAPI extern const Eina_Value_Type *EINA_VALUE_TYPE_CONTENT;
117
118/**
119 * Convert the Eina_Content object to a Eina_Value.
120 *
121 * @param[in] content The Eina_Content struct that will be converted to a Eina_Value
122 *
123 * @return A Eina_Value that is allocated, you need to free it.
124 */
125EAPI Eina_Value* eina_value_content_new(Eina_Content *content);
126
127/**
128 * Convert the Eina_Content object to a Eina_Value.
129 *
130 * @param[in] content The Eina_Content struct that will be converted to a Eina_Value
131 *
132 * @return A Eina_Value with type EINA_VALUE_TYPE_CONTENT
133 */
134EAPI Eina_Value eina_value_content_init(Eina_Content *content);
135
136/**
137 * Get the content from the Eina_Value
138 *
139 * If the value is not of the type EINA_VALUE_TYPE_CONTENT, NULL will be returned and a error will be printed.
140 *
141 * @param[in] value The value to get the content from
142 *
143 * @return A allocated Eina_Content, you need to free it.
144 */
145EAPI Eina_Content* eina_value_to_content(const Eina_Value *value);
146
147
148static inline Eina_Iterator*
149eina_content_possible_conversions(Eina_Content *content)
150{
151 return eina_content_converter_possible_conversions(eina_content_type_get(content));
152}
153
154#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;
154 S(slstr); 154 S(slstr);
155 S(promise); 155 S(promise);
156 S(vpath); 156 S(vpath);
157 S(abstract_content);
157#undef S 158#undef S
158 159
159struct eina_desc_setup 160struct eina_desc_setup
@@ -202,6 +203,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = {
202 S(safepointer), 203 S(safepointer),
203 S(slstr), 204 S(slstr),
204 S(promise), 205 S(promise),
206 S(abstract_content)
205#undef S 207#undef S
206}; 208};
207static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) / 209static 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);
464#else 464#else
465#define EINA_SLICE_STR(str) {.len = strlen((str)), .mem = (str)} 465#define EINA_SLICE_STR(str) {.len = strlen((str)), .mem = (str)}
466#endif 466#endif
467/**
468 * @def EINA_SLICE_STR_FULL(str)
469 *
470 * Same as EINA_SLICE_STR_FULL, but it also contains the \0 element of the string
471 *
472 * @param[in] str The string to create the slice from.
473 * @return The initialized slice object.
474 *
475 * @note This macro is usable with both Eina_Slice or Eina_Rw_Slice.
476 *
477 * @code
478 * Eina_Slice ro_slice = EINA_SLICE_STR_FULL("hello world");
479 * @endcode
480 *
481 * @see EINA_SLICE_STR_FULL() for specific version using literals.
482 *
483 * @since 1.24
484 */
485#ifdef __cplusplus
486#define EINA_SLICE_STR_FULL(str) {strlen((str)) + 1, (str)}
487#else
488#define EINA_SLICE_STR_FULL(str) {.len = strlen((str)) + 1, .mem = (str)}
489#endif
490
467 491
468/** 492/**
469 * @def EINA_SLICE_STR_FMT 493 * @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 = [
107'eina_freeq.h', 107'eina_freeq.h',
108'eina_slstr.h', 108'eina_slstr.h',
109'eina_vpath.h', 109'eina_vpath.h',
110'eina_abstract_content.h'
110] 111]
111 112
112public_headers = [ 113public_headers = [
@@ -188,7 +189,8 @@ sources = [
188'eina_freeq.c', 189'eina_freeq.c',
189'eina_slstr.c', 190'eina_slstr.c',
190'eina_vpath.c', 191'eina_vpath.c',
191'eina_vpath_xdg.c' 192'eina_vpath_xdg.c',
193'eina_abstract_content.c',
192] 194]
193 195
194if sys_windows == true 196if 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[] = {
90 { "slstr", eina_test_slstr }, 90 { "slstr", eina_test_slstr },
91 { "Vpath", eina_test_vpath }, 91 { "Vpath", eina_test_vpath },
92 { "debug", eina_test_debug }, 92 { "debug", eina_test_debug },
93 { "Abstract Content", eina_test_abstract_content },
93 { NULL, NULL } 94 { NULL, NULL }
94}; 95};
95 96
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);
78void eina_test_slstr(TCase *tc); 78void eina_test_slstr(TCase *tc);
79void eina_test_vpath(TCase *tc); 79void eina_test_vpath(TCase *tc);
80void eina_test_debug(TCase *tc); 80void eina_test_debug(TCase *tc);
81void eina_test_abstract_content(TCase *tc);
81 82
82#endif /* EINA_SUITE_H_ */ 83#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 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdio.h>
6
7#include <Eina.h>
8
9#include "eina_suite.h"
10
11EFL_START_TEST(eina_test_content_create_destroy)
12{
13 const char *text_str = "TestAsDf";
14 Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain");
15
16 ck_assert_str_eq(eina_content_type_get(content), "text/plain");
17 ck_assert_int_eq(eina_content_data_get(content).len, strlen(text_str) + 1);
18 ck_assert_str_eq(eina_content_data_get(content).mem, text_str);
19
20 eina_content_free(content);
21}
22EFL_END_TEST
23
24EFL_START_TEST(eina_test_content_as_file)
25{
26 const char *text_str = "TestAsDf";
27 Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain");
28 Eina_File *f;
29 const char *file_path = eina_content_as_file(content);
30
31 f = eina_file_open(file_path, EINA_FALSE);
32 const char *file_content = eina_file_map_all(f, EINA_FILE_POPULATE);
33 ck_assert_str_eq(file_content, text_str);
34 eina_file_close(f);
35
36 eina_content_free(content);
37
38 const char *file_path2 = eina_content_as_file(content);
39 ck_assert_str_eq(file_path, file_path2);
40}
41EFL_END_TEST
42
43EFL_START_TEST(eina_test_content_convert_none_existing)
44{
45 const char *text_str = "TestAsDf";
46 Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain");
47
48 EXPECT_ERROR_START;
49 ck_assert_ptr_eq(eina_content_convert(content, "ThisIsReallyNotHere"), NULL);
50 EXPECT_ERROR_END;
51}
52EFL_END_TEST
53
54EFL_START_TEST(eina_test_content_convert_ascii_to_utf8)
55{
56 const char *text_str = "TestAsDf";
57 Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain");
58 Eina_Content *c = eina_content_convert(content, "text/plain;charset=utf-8");
59
60 ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=utf-8");
61 ck_assert_str_eq(eina_content_data_get(c).mem, text_str);
62}
63EFL_END_TEST
64
65EFL_START_TEST(eina_test_content_convert_ascii_to_latin)
66{
67 const char *text_str = "TestAsDf";
68 Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str), "text/plain");
69 Eina_Content *c = eina_content_convert(content, "text/plain;charset=iso-8859-1");
70
71 ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=iso-8859-1");
72 ck_assert_str_eq(eina_content_data_get(c).mem, text_str);
73}
74EFL_END_TEST
75
76EFL_START_TEST(eina_test_content_convert_utf8_to_latin)
77{
78 //this means AÄÜÖß
79 const char text_str[] = {'A', 0xc3, 0x84, 0xc3, 0x9c, 0xc3, 0x96, 0xc3, 0x9f, 0};
80 const char text_str_latin[] = {'A', 0xC4, 0xDC, 0xD6, 0xDF, 0};
81 Eina_Content *content = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(text_str_latin), "text/plain;charset=iso-8859-1");
82 Eina_Content *c = eina_content_convert(content, "text/plain;charset=utf-8");
83
84 ck_assert_str_eq(eina_content_type_get(c), "text/plain;charset=utf-8");
85 ck_assert_int_eq(sizeof(text_str), eina_content_data_get(c).len);
86 for (unsigned int i = 0; i < eina_content_data_get(c).len; ++i)
87 {
88 ck_assert_int_eq(text_str[i], ((char*)eina_content_data_get(c).mem)[i]);
89 }
90 ck_assert_str_eq(eina_content_data_get(c).mem, text_str);
91}
92EFL_END_TEST
93
94EFL_START_TEST(eina_test_content_possible_converstions)
95{
96 ck_assert_int_eq(eina_content_converter_convert_can("text/plain", "text/plain;charset=utf-8"), 1);
97 ck_assert_int_eq(eina_content_converter_convert_can("text/plain", "ThisDoesNotExist"), 0);
98 ck_assert_int_eq(eina_content_converter_convert_can("ThisDoesNotExist", "text/plain;charset=utf-8"), 0);
99 Eina_Iterator *iterator = eina_content_converter_possible_conversions("text/plain");
100 char *text;
101 int i = 0, j = 0;
102
103 EINA_ITERATOR_FOREACH(iterator, text)
104 {
105 if (eina_streq(text, "text/plain;charset=utf-8"))
106 i ++;
107 if (eina_streq(text, "text/plain;charset=iso-8859-1"))
108 j ++;
109 }
110 ck_assert_int_eq(i, 1);
111 ck_assert_int_eq(j, 1);
112 eina_iterator_free(iterator);
113}
114EFL_END_TEST
115
116static Eina_Bool getting_called = EINA_FALSE;
117
118static Eina_Content*
119_test_cb(Eina_Content *content EINA_UNUSED, const char *type EINA_UNUSED)
120{
121 getting_called = EINA_TRUE;
122 return eina_content_new(eina_content_data_get(content), type);
123}
124
125EFL_START_TEST(eina_test_register_illegal)
126{
127 const char *test_str = "AbCdEfG";
128 eina_content_converter_conversion_register("Test", "Test2", _test_cb);
129 EXPECT_ERROR_START;
130 eina_content_converter_conversion_register("Test", "Test2", _test_cb);
131 EXPECT_ERROR_END;
132
133 Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(test_str), "Test");
134 Eina_Content *c2 = eina_content_convert(c, "Test2");
135 ck_assert_ptr_ne(c2, NULL);
136 ck_assert_int_eq(getting_called, EINA_TRUE);
137}
138EFL_END_TEST
139
140EFL_START_TEST(eina_test_content_value)
141{
142 const char *str_a = "All";
143 const char *str_b = "Out";
144 Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain");
145 Eina_Content *b = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_b), "text/plain");
146 Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain");
147 Eina_Content *d = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "Not_Text");
148 Eina_Value *va = eina_value_content_new(a);
149 Eina_Value *vb = eina_value_content_new(b);
150 Eina_Value *vc = eina_value_content_new(c);
151 Eina_Value *vd = eina_value_content_new(d);
152 Eina_Value *vcopy = eina_value_new(EINA_VALUE_TYPE_CONTENT);
153 Eina_Content *content;
154
155 ck_assert_int_eq(eina_value_compare(va, vc), 0);
156 ck_assert_int_ne(eina_value_compare(va, vb), 0);
157 ck_assert_int_ne(eina_value_compare(va, vd), 0);
158 ck_assert_int_eq(eina_value_compare(vd, vd), 0);
159
160 ck_assert_int_eq(eina_value_copy(va, vcopy), 1);
161 ck_assert_int_eq(eina_value_compare(va, vcopy), 0);
162
163 content = eina_value_to_content(vcopy);
164 Eina_Slice slice = eina_content_data_get(content);
165 ck_assert_int_eq(slice.len, strlen(str_a) + 1);
166 ck_assert_str_eq(slice.mem, str_a);
167
168 ck_assert_str_eq(eina_content_type_get(content), "text/plain");
169 eina_content_free(content);
170}
171EFL_END_TEST
172
173EFL_START_TEST(eina_test_content_value_set)
174{
175 const char *str_a = "All";
176 Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain");
177 Eina_Value *acopy = eina_value_new(EINA_VALUE_TYPE_CONTENT);
178 Eina_Content *content;
179
180 eina_value_set(acopy, a);
181 content = eina_value_to_content(acopy);
182 Eina_Slice slice = eina_content_data_get(content);
183 ck_assert_int_eq(slice.len, strlen(str_a) + 1);
184 ck_assert_str_eq(slice.mem, str_a);
185
186 ck_assert_str_eq(eina_content_type_get(content), "text/plain");
187 eina_content_free(content);
188}
189EFL_END_TEST
190
191EFL_START_TEST(eina_test_content_value_convertion)
192{
193 const char *str_a = "All";
194 const char *str_b = "Out";
195 const char *str_c = "Life";
196 Eina_Content *a = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_a), "text/plain;charset=utf-8");
197 Eina_Content *b = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_b), "text/plain");
198 Eina_Content *c = eina_content_new((Eina_Slice)EINA_SLICE_STR_FULL(str_c), "application/x-elementary-markup");
199 Eina_Value *av = eina_value_content_new(a);
200 Eina_Value *bv = eina_value_content_new(b);
201 Eina_Value *cv = eina_value_content_new(c);
202
203 ck_assert_str_eq(eina_value_to_string(av), str_a);
204 ck_assert_str_eq(eina_value_to_string(bv), str_b);
205 ck_assert_str_ne(eina_value_to_string(cv), str_c);
206}
207EFL_END_TEST
208
209void
210eina_test_abstract_content(TCase *tc)
211{
212 tcase_add_test(tc, eina_test_content_create_destroy);
213 tcase_add_test(tc, eina_test_content_as_file);
214 tcase_add_test(tc, eina_test_content_convert_none_existing);
215 tcase_add_test(tc, eina_test_content_convert_ascii_to_utf8);
216 tcase_add_test(tc, eina_test_content_convert_ascii_to_latin);
217 tcase_add_test(tc, eina_test_content_convert_utf8_to_latin);
218 tcase_add_test(tc, eina_test_content_possible_converstions);
219 tcase_add_test(tc, eina_test_register_illegal);
220 tcase_add_test(tc, eina_test_content_value);
221 tcase_add_test(tc, eina_test_content_value_set);
222 tcase_add_test(tc, eina_test_content_value_convertion);
223}
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(
54'eina_test_slice.c', 54'eina_test_slice.c',
55'eina_test_freeq.c', 55'eina_test_freeq.c',
56'eina_test_slstr.c', 56'eina_test_slstr.c',
57'eina_test_vpath.c' 57'eina_test_vpath.c',
58'eina_test_abstract_content.c',
58) 59)
59 60
60 61