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