aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/evas/src/modules/loaders/generic/evas_image_load_generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/evas/src/modules/loaders/generic/evas_image_load_generic.c')
-rw-r--r--libraries/evas/src/modules/loaders/generic/evas_image_load_generic.c430
1 files changed, 430 insertions, 0 deletions
diff --git a/libraries/evas/src/modules/loaders/generic/evas_image_load_generic.c b/libraries/evas/src/modules/loaders/generic/evas_image_load_generic.c
new file mode 100644
index 0000000..88c189d
--- /dev/null
+++ b/libraries/evas/src/modules/loaders/generic/evas_image_load_generic.c
@@ -0,0 +1,430 @@
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
19static 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);
20static 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
22Evas_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
30static Eina_Bool
31illegal_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
57static void
58escape_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
94static void
95dotcat(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
105static 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 }
287getdata:
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
385static Eina_Bool
386evas_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
391static Eina_Bool
392evas_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
402static int
403module_open(Evas_Module *em)
404{
405 if (!em) return 0;
406 em->functions = (void *)(&evas_image_load_generic_func);
407 return 1;
408}
409
410static void
411module_close(Evas_Module *em __UNUSED__)
412{
413}
414
415static 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
426EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, generic);
427
428#ifndef EVAS_STATIC_BUILD_GENERIC
429EVAS_EINA_MODULE_DEFINE(image_loader, generic);
430#endif