Revert "Rollback to previous package. evas_1.0.0.001+svn.62695slp2+build31"
[framework/uifw/evas.git] / src / modules / loaders / generic / evas_image_load_generic.c
1 #ifdef HAVE_CONFIG_H
2 # include "config.h"
3 #endif
4
5 #ifdef HAVE_EVIL
6 # include <Evil.h>
7 #endif
8
9 #include "evas_common.h"
10 #include "evas_private.h"
11
12 #include <stdio.h>
13 #include <sys/types.h>
14 #include <sys/mman.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <ctype.h>
18
19 static Eina_Bool evas_image_load_file_head_generic(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
20 static Eina_Bool evas_image_load_file_data_generic(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4);
21
22 Evas_Image_Load_Func evas_image_load_generic_func =
23 {
24   EINA_TRUE,
25   evas_image_load_file_head_generic,
26   evas_image_load_file_data_generic,
27   NULL
28 };
29
30 static Eina_Bool
31 illegal_char(const char *str)
32 {
33    const char *p;
34
35    for (p = str; *p; p++)
36      {
37         if (*p <  '-')  return EINA_TRUE;
38         if (*p == '/')  return EINA_TRUE;
39         if (*p == ';')  return EINA_TRUE;
40         if (*p == ':')  return EINA_TRUE;
41         if (*p == '<')  return EINA_TRUE;
42         if (*p == '>')  return EINA_TRUE;
43         if (*p == '?')  return EINA_TRUE;
44         if (*p == '[')  return EINA_TRUE;
45         if (*p == '\\') return EINA_TRUE;
46         if (*p == ']')  return EINA_TRUE;
47         if (*p == '`')  return EINA_TRUE;
48         if (*p == '{')  return EINA_TRUE;
49         if (*p == '|')  return EINA_TRUE;
50         if (*p == '}')  return EINA_TRUE;
51         if (*p == '~')  return EINA_TRUE;
52         if (*p == 0x7f) return EINA_TRUE;
53      }
54    return EINA_FALSE;
55 }
56
57 static void
58 escape_copy(const char *src, char *dst)
59 {
60    const char *s;
61    char *d;
62
63    for (s = src, d = dst; *s; s++, d++)
64      {
65         // FIXME: escape tab, newline linefeed and friends
66         if ((*s == ' ')  ||
67             (*s == '!')  ||
68             (*s == '"')  ||
69             (*s == '#')  ||
70             (*s == '$')  ||
71             (*s == '%')  ||
72             (*s == '&')  ||
73             (*s == '\'') ||
74             (*s == '(')  ||
75             (*s == ')')  ||
76             (*s == '*')  ||
77             (*s == '[')  ||
78             (*s == '\\') ||
79             (*s == ']')  ||
80             (*s == '`')  ||
81             (*s == '{')  ||
82             (*s == '|')  ||
83             (*s == '}')  ||
84             (*s == '~'))
85           {
86              *d = '\\';
87              d++;
88           }
89         *d = *s;
90      }
91    *d = 0;
92 }
93
94 static void
95 dotcat(char *dest, const char *src)
96 {
97    int len = strlen(dest);
98    const char *s;
99    char *d;
100
101    for (d = dest + len, s = src; *s; d++, s++) *d = tolower(*s);
102    *d = 0;
103 }
104
105 static Eina_Bool
106 _load(Image_Entry *ie, const char *file, const char *key, int *error, Eina_Bool get_data)
107 {
108    Eina_Bool res = EINA_FALSE;
109    int w = 0, h = 0, alpha = 0;
110    const char *dot1 = NULL, *dot2 = NULL, *end, *p;
111    char *cmd = NULL, decoders[3][128], buf[4096];
112    char *loader = "/evas/utils/evas_image_loader";
113    char *img_loader = NULL;
114    const char *libdir;
115    // eg $libdir/evas/generic_loaders
116    int cmd_len, len, decoders_num = 0, try_count = 0;
117    int read_data = 0;
118    char *tmpfname = NULL, *shmfname = NULL;
119    DATA32 *body;
120    FILE *f;
121
122    libdir = _evas_module_libdir_get();
123    cmd_len = strlen(libdir);
124    cmd_len += strlen(loader);
125    img_loader = alloca(cmd_len + 1);
126    strcpy(img_loader, libdir);
127    strcat(img_loader, loader);
128    // params excluding file, key and loadopts
129    cmd_len += 1024;
130    cmd_len += strlen(file) * 2;
131    if (key) cmd_len += strlen(key) * 2;
132    cmd = alloca(cmd_len + 1);
133
134    len = strlen(file);
135    if (len < 1)
136      {
137         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
138         return EINA_FALSE;
139      }
140    end = file + len;
141    for (p = end - 1; p >= file; p--)
142      {
143         if      ((!dot1) && (*p == '.')) dot1 = p;
144         else if ((!dot2) && (*p == '.')) dot2 = p;
145         else if ((dot1) && (dot2)) break;
146     }
147    if (dot2)
148      {
149         // double extn not too long
150         if (((end - dot2) <= 10) && (!illegal_char(dot2)))
151           {
152              strcpy(&(decoders[decoders_num][0]), img_loader);
153              dotcat(&(decoders[decoders_num][0]), dot2);
154              decoders_num++;
155           }
156         // single extn not too long
157         if (((end - dot1) <= 5) && (!illegal_char(dot1)))
158           {
159              strcpy(&(decoders[decoders_num][0]), img_loader);
160              dotcat(&(decoders[decoders_num][0]), dot1);
161              decoders_num++;
162           }
163         strcpy(decoders[decoders_num], img_loader);
164         decoders_num++;
165      }
166    else if (dot1)
167      {
168         // single extn not too long
169         if (((end - dot1) <= 5) && (!illegal_char(dot1)))
170           {
171              strcpy(&(decoders[decoders_num][0]), img_loader);
172              dotcat(&(decoders[decoders_num][0]), dot1);
173              decoders_num++;
174           }
175         strcpy(decoders[decoders_num], img_loader);
176         decoders_num++;
177      }
178    else
179      {
180         strcpy(decoders[decoders_num], img_loader);
181         decoders_num++;
182      }
183
184    for (try_count = 0; try_count < decoders_num; try_count++)
185      {
186         // FIXME: strcats could be more efficient, not that it matters much
187         // here as we are about to build a cmd to exec via a shell that
188         // will interpret shell stuff and path hunt that will then exec the
189         // program itself that will dynamically link that will again
190         // parse the arguments and finally do something...
191         strcpy(cmd, decoders[try_count]);
192         strcat(cmd, " ");
193         // filename first arg
194         len = strlen(cmd);
195         escape_copy(file, cmd + len);
196         if (!get_data)
197           {
198              strcat(cmd, " -head ");
199           }
200         if (key)
201           {
202              strcat(cmd, " -key ");
203              len = strlen(cmd);
204              escape_copy(key, cmd + len);
205           }
206         if (ie->load_opts.scale_down_by > 1)
207           {
208              strcat(cmd, " -opt-scale-down-by ");
209              snprintf(buf, sizeof(buf), "%i", ie->load_opts.scale_down_by);
210              strcat(cmd, buf);
211           }
212         if (ie->load_opts.dpi > 0.0)
213           {
214              strcat(cmd, " -opt-dpi ");
215              snprintf(buf, sizeof(buf), "%i", (int)(ie->load_opts.dpi * 1000.0));
216              strcat(cmd, buf);
217           }
218         if ((ie->load_opts.w > 0) &&
219             (ie->load_opts.h > 0))
220           {
221              strcat(cmd, " -opt-size ");
222              snprintf(buf, sizeof(buf), "%i %i", ie->load_opts.w, ie->load_opts.h);
223              strcat(cmd, buf);
224          }
225         f = popen(cmd, "r");
226         if (f) break;
227      }
228    if (!f)
229      {
230         *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST;
231         return EINA_FALSE;
232      }
233    while (fgets(buf, sizeof(buf), f))
234      {
235         len = strlen(buf);
236         if (len > 0)
237           {
238              if ((buf[len - 1] == '\n')) buf[len - 1] = 0;
239              if (!strncmp(buf, "size ", 5))
240                {
241                   int tw = 0, th = 0;
242
243                   len = sscanf(buf, "%*s %i %i", &tw, &th);
244                   if (len == 2)
245                     {
246                        if ((tw > 0) && (th > 0))
247                          {
248                             w = tw;
249                             h = th;
250                          }
251                     }
252                }
253              else if (!strncmp(buf, "alpha ", 6))
254                {
255                   int ta;
256
257                   len = sscanf(buf, "%*s %i", &ta);
258                   if (len == 1)
259                     {
260                        alpha = ta;
261                     }
262                }
263              else if (!strncmp(buf, "tmpfile ", 8))
264                {
265                   tmpfname = buf + 8;
266                   goto getdata;
267                }
268 #ifdef HAVE_SHM_OPEN
269              else if (!strncmp(buf, "shmfile ", 8))
270                {
271                   shmfname = buf + 8;
272                   goto getdata;
273                }
274 #endif
275              else if (!strncmp(buf, "data", 4))
276                {
277                   read_data = 1;
278                   goto getdata;
279                }
280              else if (!strncmp(buf, "done", 4))
281                {
282                   read_data = 2;
283                   goto getdata;
284                }
285           }
286      }
287 getdata:
288    if ((!read_data) && (!tmpfname) && (!shmfname))
289      {
290         *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
291         goto on_error;
292      }
293    if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
294        IMG_TOO_BIG(w, h))
295      {
296         *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
297         goto on_error;
298      }
299    body = evas_cache_image_pixels(ie);
300    if (body)
301      {
302         if ((w != (int)ie->w) || (h != (int)ie->h))
303           {
304              *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
305              goto on_error;
306           }
307      }
308    if (alpha) ie->flags.alpha = 1;
309    ie->w = w;
310    ie->h = h;
311
312    if (get_data)
313      {
314         if (!body) evas_cache_image_surface_alloc(ie, ie->w, ie->h);
315         body = evas_cache_image_pixels(ie);
316         if (!body)
317           {
318              *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
319              goto on_error;
320           }
321
322         if ((tmpfname) || (shmfname))
323           {
324              int fd = -1;
325
326              // open
327              if (tmpfname)
328                 fd = open(tmpfname, O_RDONLY, S_IRUSR);
329 #ifdef HAVE_SHM_OPEN
330              else if (shmfname)
331                 fd = shm_open(shmfname, O_RDONLY, S_IRUSR);
332 #endif
333              if (fd >= 0)
334                {
335                   void *addr;
336
337                   eina_mmap_safety_enabled_set(EINA_TRUE);
338                   
339                   // mmap
340                   addr = mmap(NULL, w * h * sizeof(DATA32),
341                               PROT_READ, MAP_SHARED, fd, 0);
342                   if (addr != MAP_FAILED)
343                     {
344                        memcpy(body, addr, w * h * sizeof(DATA32));
345                        munmap(addr, w * h * sizeof(DATA32));
346                     }
347                   // close
348                   if (tmpfname)
349                     {
350                        close(fd);
351                        unlink(tmpfname);
352                     }
353 #ifdef HAVE_SHM_OPEN
354                   else if (shmfname)
355                     {
356                        close(fd);
357                        shm_unlink(shmfname);
358                     }
359 #endif
360                }
361              else
362                {
363                   *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED;
364                   goto on_error;
365                }
366           }
367         else if (read_data)
368           {
369              if (fread(body, w * h * sizeof(DATA32), 1, f) != 1)
370                {
371                   *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
372                   goto on_error;
373                }
374           }
375      }
376
377    res = EINA_TRUE;
378    *error = EVAS_LOAD_ERROR_NONE;
379
380  on_error:
381    if (f) pclose(f);
382    return res;
383 }
384
385 static Eina_Bool
386 evas_image_load_file_head_generic(Image_Entry *ie, const char *file, const char *key, int *error)
387 {
388    return _load(ie, file, key, error, EINA_FALSE);
389 }
390
391 static Eina_Bool
392 evas_image_load_file_data_generic(Image_Entry *ie, const char *file, const char *key, int *error)
393 {
394    DATA32 *body;
395
396    body = evas_cache_image_pixels(ie);
397    if (!body) return _load(ie, file, key, error, EINA_TRUE);
398    *error = EVAS_LOAD_ERROR_NONE;
399    return EINA_TRUE;
400 }
401
402 static int
403 module_open(Evas_Module *em)
404 {
405    if (!em) return 0;
406    em->functions = (void *)(&evas_image_load_generic_func);
407    return 1;
408 }
409
410 static void
411 module_close(Evas_Module *em __UNUSED__)
412 {
413 }
414
415 static Evas_Module_Api evas_modapi =
416 {
417    EVAS_MODULE_API_VERSION,
418    "generic",
419    "none",
420    {
421      module_open,
422      module_close
423    }
424 };
425
426 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, generic);
427
428 #ifndef EVAS_STATIC_BUILD_GENERIC
429 EVAS_EINA_MODULE_DEFINE(image_loader, generic);
430 #endif