1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8
9 #include "evas_common_private.h"
10 #include "evas_private.h"
11 //#include "evas_cs.h"
12
13 struct ext_loader_s
14 {
15 unsigned int length;
16 const char *extension;
17 const char *loader;
18 };
19
20 #define MATCHING(Ext, Module) \
21 { sizeof (Ext), Ext, Module }
22
23 static const struct ext_loader_s loaders[] =
24 { /* map extensions to loaders to use for good first-guess tries */
25 MATCHING(".png", "png"),
26
27 MATCHING(".jpg", "jpeg"),
28 MATCHING(".jpeg", "jpeg"),
29 MATCHING(".jfif", "jpeg"),
30
31 MATCHING(".j2k", "jp2k"),
32 MATCHING(".jp2", "jp2k"),
33 MATCHING(".jpx", "jp2k"),
34 MATCHING(".jpf", "jp2k"),
35
36 MATCHING(".eet", "eet"),
37 MATCHING(".edj", "eet"),
38 MATCHING(".eap", "eet"),
39
40 MATCHING(".xpm", "xpm"),
41
42 MATCHING(".tiff", "tiff"),
43 MATCHING(".tif", "tiff"),
44
45 MATCHING(".gif", "gif"),
46
47 MATCHING(".pbm", "pmaps"),
48 MATCHING(".pgm", "pmaps"),
49 MATCHING(".ppm", "pmaps"),
50 MATCHING(".pnm", "pmaps"),
51
52 MATCHING(".bmp", "bmp"),
53
54 MATCHING(".tga", "tga"),
55
56 MATCHING(".wbmp", "wbmp"),
57
58 MATCHING(".webp", "webp"),
59
60 MATCHING(".ico", "ico"),
61 MATCHING(".cur", "ico"),
62
63 MATCHING(".psd", "psd"),
64
65 MATCHING(".tgv", "tgv"),
66
67 MATCHING(".dds", "dds"),
68
69 MATCHING(".avif", "avif"),
70 MATCHING(".avifs", "avif"),
71
72 /* xcf - gefenric */
73 MATCHING(".xcf", "generic"),
74 MATCHING(".xcf.gz", "generic"),
75 /* docs */
76 MATCHING(".doc", "generic"),
77 MATCHING(".docx", "generic"),
78 MATCHING(".odp", "generic"),
79 MATCHING(".ods", "generic"),
80 MATCHING(".odt", "generic"),
81 MATCHING(".pdf", "generic"),
82 MATCHING(".ps", "generic"),
83 MATCHING(".ppt", "generic"),
84 MATCHING(".pptx", "generic"),
85 MATCHING(".rtf", "generic"),
86 MATCHING(".xls", "generic"),
87 MATCHING(".xlsx", "generic"),
88 /* svg - generic */
89 MATCHING(".svg", "generic"),
90 MATCHING(".svgz", "generic"),
91 MATCHING(".svg.gz", "generic"),
92 /* RAW */
93 MATCHING(".arw", "generic"),
94 MATCHING(".cr2", "generic"),
95 MATCHING(".crw", "generic"),
96 MATCHING(".dcr", "generic"),
97 MATCHING(".dng", "generic"),
98 MATCHING(".erf", "generic"),
99 MATCHING(".fff", "generic"),
100 MATCHING(".k25", "generic"),
101 MATCHING(".kdc", "generic"),
102 MATCHING(".mrw", "generic"),
103 MATCHING(".nef", "generic"),
104 MATCHING(".nrf", "generic"),
105 MATCHING(".nrw", "generic"),
106 MATCHING(".orf", "generic"),
107 MATCHING(".pef", "generic"),
108 MATCHING(".raf", "generic"),
109 MATCHING(".raw", "generic"),
110 MATCHING(".rw2", "generic"),
111 MATCHING(".sr2", "generic"),
112 MATCHING(".srf", "generic"),
113 MATCHING(".x3f", "generic"),
114 /* video */
115 MATCHING(".264", "generic"),
116 MATCHING(".3g2", "generic"),
117 MATCHING(".3gp", "generic"),
118 MATCHING(".3gp2", "generic"),
119 MATCHING(".3gpp", "generic"),
120 MATCHING(".3gpp2", "generic"),
121 MATCHING(".3p2", "generic"),
122 MATCHING(".asf", "generic"),
123 MATCHING(".avi", "generic"),
124 MATCHING(".bdm", "generic"),
125 MATCHING(".bdmv", "generic"),
126 MATCHING(".clpi", "generic"),
127 MATCHING(".cpi", "generic"),
128 MATCHING(".dv", "generic"),
129 MATCHING(".fla", "generic"),
130 MATCHING(".flv", "generic"),
131 MATCHING(".m1v", "generic"),
132 MATCHING(".m2t", "generic"),
133 MATCHING(".m2v", "generic"),
134 MATCHING(".m4v", "generic"),
135 MATCHING(".mkv", "generic"),
136 MATCHING(".mov", "generic"),
137 MATCHING(".mp2", "generic"),
138 MATCHING(".mp2ts", "generic"),
139 MATCHING(".mp4", "generic"),
140 MATCHING(".mpe", "generic"),
141 MATCHING(".mpeg", "generic"),
142 MATCHING(".mpg", "generic"),
143 MATCHING(".mpl", "generic"),
144 MATCHING(".mpls", "generic"),
145 MATCHING(".mts", "generic"),
146 MATCHING(".mxf", "generic"),
147 MATCHING(".nut", "generic"),
148 MATCHING(".nuv", "generic"),
149 MATCHING(".ogg", "generic"),
150 MATCHING(".ogm", "generic"),
151 MATCHING(".ogv", "generic"),
152 MATCHING(".qt", "generic"),
153 MATCHING(".rm", "generic"),
154 MATCHING(".rmj", "generic"),
155 MATCHING(".rmm", "generic"),
156 MATCHING(".rms", "generic"),
157 MATCHING(".rmvb", "generic"),
158 MATCHING(".rmx", "generic"),
159 MATCHING(".rv", "generic"),
160 MATCHING(".swf", "generic"),
161 MATCHING(".ts", "generic"),
162 MATCHING(".weba", "generic"),
163 MATCHING(".webm", "generic"),
164 MATCHING(".wmv", "generic")
165 };
166
167 static const char *loaders_name[] =
168 { /* in order of most likely needed */
169 "png", "jpeg", "eet", "xpm", "tiff", "gif", "svg", "webp", "pmaps",
170 "bmp", "tga", "wbmp", "ico", "psd", "jp2k", "dds", "avif", "generic"
171 };
172
173 struct evas_image_foreach_loader_data
174 {
175 Image_Entry *ie;
176 int *error;
177 Evas_Module *em;
178 };
179
180 static Eina_Bool
_evas_image_file_header(Evas_Module * em,Image_Entry * ie,int * error)181 _evas_image_file_header(Evas_Module *em, Image_Entry *ie, int *error)
182 {
183 Evas_Image_Load_Func *evas_image_load_func = NULL;
184 Eina_Bool r = EINA_TRUE;
185
186 if (!evas_module_load(em)) goto load_error;
187 evas_image_load_func = em->functions;
188 evas_module_use(em);
189 *error = EVAS_LOAD_ERROR_NONE;
190 if (evas_image_load_func && evas_image_load_func->version == EVAS_IMAGE_LOAD_VERSION)
191 {
192 Evas_Image_Property property;
193 const char *file;
194
195 if (!ie->f)
196 {
197 ie->f = eina_file_open(ie->file, EINA_FALSE);
198 ie->flags.given_mmap = EINA_FALSE;
199 file = ie->file;
200 }
201 else file = eina_file_filename_get(ie->f);
202
203 if (!ie->f)
204 {
205 *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
206 goto load_error;
207 }
208
209 ie->loader_data = evas_image_load_func->file_open(ie->f, ie->key,
210 &ie->load_opts,
211 &ie->animated,
212 error);
213 if (!ie->loader_data) goto load_error;
214
215 memset(&property, 0, sizeof (property));
216 if (evas_image_load_func->file_head(ie->loader_data, &property,
217 error) &&
218 (*error == EVAS_LOAD_ERROR_NONE))
219 {
220 DBG("loaded file head using module '%s' (%p): %s",
221 em->definition->name, em, file);
222
223 ie->w = property.info.w;
224 ie->h = property.info.h;
225 ie->borders.l = property.info.borders.l;
226 ie->borders.r = property.info.borders.r;
227 ie->borders.t = property.info.borders.t;
228 ie->borders.b = property.info.borders.b;
229 ie->scale = property.info.scale;
230 ie->flags.alpha = property.info.alpha;
231 ie->need_data = property.need_data;
232 if (property.info.cspaces) ie->cspaces = property.info.cspaces;
233 ie->flags.rotated = property.info.rotated;
234 ie->flags.flipped = property.info.flipped;
235 r = EINA_FALSE;
236 }
237 else
238 {
239 evas_image_load_func->file_close(ie->loader_data);
240 ie->loader_data = NULL;
241 evas_module_unload(em);
242 INF("failed to load file head using module '%s' (%p): "
243 "%s (%s)",
244 em->definition->name, em, file, evas_load_error_str(*error));
245 }
246 }
247 else
248 {
249 load_error:
250 evas_module_unload(em);
251 WRN("failed to load module '%s'.", em->definition->name);
252 }
253 return r;
254 }
255
256 static Eina_Bool
_evas_image_foreach_loader(const Eina_Hash * hash EINA_UNUSED,const void * key EINA_UNUSED,void * data,void * fdata)257 _evas_image_foreach_loader(const Eina_Hash *hash EINA_UNUSED, const void *key EINA_UNUSED, void *data, void *fdata)
258 {
259 struct evas_image_foreach_loader_data *d = fdata;
260 Evas_Module *em = data;
261 Image_Entry *ie = d->ie;
262 Eina_Bool r;
263
264 r = _evas_image_file_header(em, ie, d->error);
265 if (!r) d->em = em;
266 return r;
267 }
268
269 EAPI int
evas_common_load_rgba_image_module_from_file(Image_Entry * ie)270 evas_common_load_rgba_image_module_from_file(Image_Entry *ie)
271 {
272 const char *loader = NULL, *end;
273 const char *file;
274 Evas_Module *em;
275 unsigned int i;
276 int len, ret = EVAS_LOAD_ERROR_NONE;
277 struct evas_image_foreach_loader_data fdata;
278 Eina_Bool skip;
279
280 skip = ie->load_opts.skip_head;
281 if (ie->f)
282 {
283 len = strlen(eina_file_filename_get(ie->f));
284 end = eina_file_filename_get(ie->f) + len;
285 file = eina_file_filename_get(ie->f);
286 }
287 else
288 {
289 if (!skip)
290 {
291 struct stat st;
292
293 if (stat(ie->file, &st) != 0 || S_ISDIR(st.st_mode))
294 {
295 DBG("trying to open directory '%s' !", ie->file);
296 return EVAS_LOAD_ERROR_DOES_NOT_EXIST;
297 }
298 }
299 len = strlen(ie->file);
300 end = ie->file + len;
301 file = ie->file;
302 }
303
304 for (i = 0; i < (sizeof (loaders) / sizeof(struct ext_loader_s)); i++)
305 {
306 int len2 = strlen(loaders[i].extension);
307 if (len2 > len) continue;
308 if (!strcasecmp(end - len2, loaders[i].extension))
309 {
310 loader = loaders[i].loader;
311 DBG("known loader '%s' handles extension '%s' of file '%s'",
312 loader, end - len2, file);
313 break;
314 }
315 }
316
317 if (loader)
318 {
319 em = evas_module_find_type(EVAS_MODULE_TYPE_IMAGE_LOADER, loader);
320 if (em)
321 {
322 if (!((Evas_Image_Load_Func *)em->functions)->threadable)
323 skip = EINA_FALSE;
324 DBG("found image loader '%s' (%p)", loader, em);
325 if (!skip)
326 {
327 if (!_evas_image_file_header(em, ie, &ret)) goto end;
328 }
329 }
330 else INF("image loader '%s' is not enabled or missing!", loader);
331 if (skip) goto end;
332 }
333
334 fdata.ie = ie;
335 fdata.error = &ret;
336 fdata.em = NULL;
337 ret = EVAS_LOAD_ERROR_NONE;
338 evas_module_foreach_image_loader(_evas_image_foreach_loader, &fdata);
339 em = fdata.em;
340 if (em) goto end;
341
342 /* This is our last chance, try all known image loader. */
343 /* FIXME: We could use eina recursive module search ability. */
344 for (i = 0; i < sizeof (loaders_name) / sizeof (char *); i++)
345 {
346 em = evas_module_find_type(EVAS_MODULE_TYPE_IMAGE_LOADER, loaders_name[i]);
347 if (em)
348 {
349 if (!ie->load_opts.skip_head)
350 {
351 if (!_evas_image_file_header(em, ie, &ret)) goto end;
352 }
353 }
354 else
355 DBG("could not find module '%s'", loaders_name[i]);
356 }
357 INF("exhausted all means to load image '%s'", file);
358 return EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
359
360 end:
361 DBG("loader '%s' used for file %s",
362 (em && em->definition && em->definition->name) ?
363 em->definition->name : "<UNKNOWN>",
364 file);
365
366 if (em)
367 {
368 ie->info.module = em;
369 ie->info.loader = em->functions;
370 evas_module_ref(em);
371 }
372 else
373 {
374 ie->info.module = NULL;
375 ie->info.loader = NULL;
376 }
377 return ret;
378 }
379
380 static void
_timestamp_build(Image_Timestamp * tstamp,struct stat * st)381 _timestamp_build(Image_Timestamp *tstamp, struct stat *st)
382 {
383 tstamp->mtime = st->st_mtime;
384 tstamp->size = st->st_size;
385 tstamp->ino = st->st_ino;
386 #ifdef _STAT_VER_LINUX
387 # if (defined __USE_MISC && defined st_mtime)
388 tstamp->mtime_nsec = (unsigned long int)st->st_mtim.tv_nsec;
389 # else
390 tstamp->mtime_nsec = (unsigned long int)st->st_mtimensec;
391 # endif
392 #endif
393 }
394
395 EAPI int
evas_common_load_rgba_image_data_from_file(Image_Entry * ie)396 evas_common_load_rgba_image_data_from_file(Image_Entry *ie)
397 {
398 void *pixels;
399 Evas_Image_Load_Func *evas_image_load_func = NULL;
400 Evas_Image_Property property;
401 int ret = EVAS_LOAD_ERROR_NONE;
402 struct stat st;
403 unsigned int i;
404
405 if ((ie->flags.loaded) && (!ie->animated.animated)) return EVAS_LOAD_ERROR_GENERIC;
406
407 if (!ie->info.module)
408 {
409 ie->load_failed = 1;
410 return EVAS_LOAD_ERROR_GENERIC;
411 }
412
413 evas_image_load_func = ie->info.loader;
414 evas_module_use(ie->info.module);
415
416 if (!ie->loader_data)
417 {
418 Evas_Module *em = ie->info.module;
419
420 if (_evas_image_file_header(em, ie, &ret))
421 {
422 em = NULL;
423 if (!ie->load_opts.skip_head)
424 {
425 for (i = 0; i < sizeof(loaders_name) / sizeof (char *); i++)
426 {
427 em = evas_module_find_type
428 (EVAS_MODULE_TYPE_IMAGE_LOADER, loaders_name[i]);
429 if (em)
430 {
431 if (!_evas_image_file_header(em, ie, &ret))
432 goto end;
433 }
434 else DBG("could not find module '%s'", loaders_name[i]);
435 em = NULL;
436 }
437 }
438 }
439 end:
440 if (ie->info.module != em)
441 {
442 if (em) evas_module_ref(em);
443 evas_module_unref(ie->info.module);
444 ie->info.module = em;
445 }
446 }
447 if ((!ie->f) || (!ie->info.module) || (!ie->loader_data))
448 {
449 ie->load_failed = 1;
450 return EVAS_LOAD_ERROR_DOES_NOT_EXIST;
451 }
452
453 if ((ie->file) && (stat(ie->file, &st) == 0))
454 _timestamp_build(&(ie->tstamp), &st);
455
456 memset(&property, 0, sizeof (property));
457 property.info.w = ie->w;
458 property.info.h = ie->h;
459 property.info.scale = ie->scale;
460 property.info.rotated = ie->flags.rotated;
461 property.info.flipped = ie->flags.flipped;
462 property.info.premul = EINA_FALSE;
463 property.info.alpha_sparse = EINA_FALSE;
464 property.info.cspace = ie->space;
465
466 evas_cache_image_surface_alloc(ie, ie->w, ie->h);
467 property.info.borders.l = ie->borders.l;
468 property.info.borders.r = ie->borders.r;
469 property.info.borders.t = ie->borders.t;
470 property.info.borders.b = ie->borders.b;
471
472 pixels = evas_cache_image_pixels(ie);
473 if (!pixels)
474 {
475 ie->load_failed = 1;
476 return EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
477 }
478
479 if (ie->need_data)
480 {
481 evas_image_load_func->file_head_with_data(ie->loader_data, &property, pixels, &ret);
482 memcpy(&ie->content, &property.content, sizeof (Eina_Rectangle));
483 ie->stretch.horizontal.region = property.stretch.horizontal.region;
484 ie->stretch.vertical.region = property.stretch.vertical.region;
485 }
486 else
487 {
488 evas_image_load_func->file_data(ie->loader_data, &property, pixels, &ret);
489 }
490
491 ie->flags.alpha_sparse = property.info.alpha_sparse;
492
493 if (property.info.premul) evas_common_image_premul(ie);
494
495 return ret;
496 }
497
498 EAPI double
evas_common_load_rgba_image_frame_duration_from_file(Image_Entry * ie,const int start,const int frame_num)499 evas_common_load_rgba_image_frame_duration_from_file(Image_Entry *ie, const int start, const int frame_num)
500 {
501 Evas_Image_Load_Func *evas_image_load_func = NULL;
502
503 if (!ie->info.module) return -1;
504
505 evas_image_load_func = ie->info.loader;
506 evas_module_use(ie->info.module);
507 if (evas_image_load_func->frame_duration)
508 {
509 if (!ie->f) return -1;
510 return evas_image_load_func->frame_duration(ie->loader_data, start, frame_num);
511 }
512 return -1;
513 }
514
515 EAPI Eina_Bool
evas_common_extension_can_load_get(const char * file)516 evas_common_extension_can_load_get(const char *file)
517 {
518 unsigned int length;
519 unsigned int i;
520
521 length = eina_stringshare_strlen(file) + 1;
522
523 for (i = 0; i < sizeof (loaders) / sizeof (struct ext_loader_s); ++i)
524 {
525 if (loaders[i].length > length) continue;
526
527 if (!strcasecmp(loaders[i].extension, file + length - loaders[i].length))
528 {
529 if ((file[length - loaders[i].length] != '/') ||
530 (length == loaders[i].length))
531 return EINA_TRUE;
532 }
533 }
534 return EINA_FALSE;
535 }
536