diff options
Diffstat (limited to 'libraries/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c')
-rw-r--r-- | libraries/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c | 558 |
1 files changed, 558 insertions, 0 deletions
diff --git a/libraries/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c b/libraries/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c new file mode 100644 index 0000000..9ba8f81 --- /dev/null +++ b/libraries/evas/src/modules/loaders/pmaps/evas_image_load_pmaps.c | |||
@@ -0,0 +1,558 @@ | |||
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 | #define FILE_BUFFER_SIZE 1024 * 32 | ||
13 | #define FILE_BUFFER_UNREAD_SIZE 16 | ||
14 | |||
15 | static Eina_Bool evas_image_load_file_head_pmaps(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4); | ||
16 | static Eina_Bool evas_image_load_file_data_pmaps(Image_Entry *ie, const char *file, const char *key, int *error) EINA_ARG_NONNULL(1, 2, 4); | ||
17 | |||
18 | Evas_Image_Load_Func evas_image_load_pmaps_func = { | ||
19 | EINA_TRUE, | ||
20 | evas_image_load_file_head_pmaps, | ||
21 | evas_image_load_file_data_pmaps, | ||
22 | NULL | ||
23 | }; | ||
24 | |||
25 | /* The buffer to load pmaps images */ | ||
26 | typedef struct Pmaps_Buffer Pmaps_Buffer; | ||
27 | |||
28 | struct Pmaps_Buffer | ||
29 | { | ||
30 | FILE *file; | ||
31 | |||
32 | /* the buffer */ | ||
33 | DATA8 buffer[FILE_BUFFER_SIZE]; | ||
34 | DATA8 unread[FILE_BUFFER_UNREAD_SIZE]; | ||
35 | DATA8 *current; | ||
36 | DATA8 *end; | ||
37 | char type[3]; | ||
38 | unsigned char unread_len:7; | ||
39 | unsigned char last_buffer:1; | ||
40 | |||
41 | /* image properties */ | ||
42 | int w; | ||
43 | int h; | ||
44 | int max; | ||
45 | |||
46 | /* interface */ | ||
47 | int (*int_get) (Pmaps_Buffer *b, int *val); | ||
48 | int (*color_get) (Pmaps_Buffer *b, DATA32 *color); | ||
49 | }; | ||
50 | |||
51 | /* internal used functions */ | ||
52 | static Eina_Bool pmaps_buffer_open(Pmaps_Buffer *b, const char *filename, int *error); | ||
53 | static void pmaps_buffer_close(Pmaps_Buffer *b); | ||
54 | static Eina_Bool pmaps_buffer_header_parse(Pmaps_Buffer *b, int *error); | ||
55 | static int pmaps_buffer_plain_int_get(Pmaps_Buffer *b, int *val); | ||
56 | static int pmaps_buffer_1byte_int_get(Pmaps_Buffer *b, int *val); | ||
57 | static int pmaps_buffer_2byte_int_get(Pmaps_Buffer *b, int *val); | ||
58 | static int pmaps_buffer_gray_get(Pmaps_Buffer *b, DATA32 *color); | ||
59 | static int pmaps_buffer_rgb_get(Pmaps_Buffer *b, DATA32 *color); | ||
60 | static int pmaps_buffer_plain_bw_get(Pmaps_Buffer *b, DATA32 *color); | ||
61 | |||
62 | static size_t pmaps_buffer_plain_update(Pmaps_Buffer *b); | ||
63 | static size_t pmaps_buffer_raw_update(Pmaps_Buffer *b); | ||
64 | static int pmaps_buffer_comment_skip(Pmaps_Buffer *b); | ||
65 | |||
66 | static Eina_Bool | ||
67 | evas_image_load_file_head_pmaps(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error) | ||
68 | { | ||
69 | Pmaps_Buffer b; | ||
70 | |||
71 | if (!pmaps_buffer_open(&b, file, error)) | ||
72 | { | ||
73 | pmaps_buffer_close(&b); | ||
74 | return EINA_FALSE; | ||
75 | } | ||
76 | |||
77 | if (!pmaps_buffer_header_parse(&b, error)) | ||
78 | { | ||
79 | pmaps_buffer_close(&b); | ||
80 | return EINA_FALSE; | ||
81 | } | ||
82 | |||
83 | ie->w = b.w; | ||
84 | ie->h = b.h; | ||
85 | |||
86 | pmaps_buffer_close(&b); | ||
87 | *error = EVAS_LOAD_ERROR_NONE; | ||
88 | return EINA_TRUE; | ||
89 | } | ||
90 | |||
91 | static Eina_Bool | ||
92 | evas_image_load_file_data_pmaps(Image_Entry *ie, const char *file, const char *key __UNUSED__, int *error) | ||
93 | { | ||
94 | Pmaps_Buffer b; | ||
95 | int pixels; | ||
96 | DATA32 *ptr; | ||
97 | |||
98 | if (!pmaps_buffer_open(&b, file, error)) | ||
99 | { | ||
100 | pmaps_buffer_close(&b); | ||
101 | return EINA_FALSE; | ||
102 | } | ||
103 | |||
104 | if (!pmaps_buffer_header_parse(&b, error)) | ||
105 | { | ||
106 | pmaps_buffer_close(&b); | ||
107 | return EINA_FALSE; | ||
108 | } | ||
109 | |||
110 | pixels = b.w * b.h; | ||
111 | |||
112 | evas_cache_image_surface_alloc(ie, b.w, b.h); | ||
113 | ptr = evas_cache_image_pixels(ie); | ||
114 | if (!ptr) | ||
115 | { | ||
116 | pmaps_buffer_close(&b); | ||
117 | *error = EVAS_LOAD_ERROR_RESOURCE_ALLOCATION_FAILED; | ||
118 | return EINA_FALSE; | ||
119 | } | ||
120 | |||
121 | if (b.type[1] != '4') | ||
122 | { | ||
123 | while (pixels > 0 && b.color_get(&b, ptr)) | ||
124 | { | ||
125 | pixels--; | ||
126 | ptr++; | ||
127 | } | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | while (pixels > 0 | ||
132 | && (b.current != b.end || pmaps_buffer_raw_update(&b))) | ||
133 | { | ||
134 | int i; | ||
135 | |||
136 | for (i = 7; i >= 0 && pixels > 0; i--) | ||
137 | { | ||
138 | if (*b.current & (1 << i)) | ||
139 | *ptr = 0xff000000; | ||
140 | else | ||
141 | *ptr = 0xffffffff; | ||
142 | ptr++; | ||
143 | pixels--; | ||
144 | } | ||
145 | b.current++; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /* if there are some pix missing, give them a proper default */ | ||
150 | memset(ptr, 0xff, 4 * pixels); | ||
151 | pmaps_buffer_close(&b); | ||
152 | |||
153 | *error = EVAS_LOAD_ERROR_NONE; | ||
154 | return EINA_TRUE; | ||
155 | } | ||
156 | |||
157 | /* internal used functions */ | ||
158 | static Eina_Bool | ||
159 | pmaps_buffer_open(Pmaps_Buffer *b, const char *filename, int *error) | ||
160 | { | ||
161 | size_t len; | ||
162 | |||
163 | b->file = fopen(filename, "rb"); | ||
164 | if (!b->file) | ||
165 | { | ||
166 | *error = EVAS_LOAD_ERROR_DOES_NOT_EXIST; | ||
167 | return EINA_FALSE; | ||
168 | } | ||
169 | |||
170 | *b->buffer = 0; | ||
171 | *b->unread = 0; | ||
172 | b->last_buffer = 0; | ||
173 | b->unread_len = 0; | ||
174 | |||
175 | len = pmaps_buffer_plain_update(b); | ||
176 | |||
177 | if (len < 3) | ||
178 | { | ||
179 | *error = EVAS_LOAD_ERROR_CORRUPT_FILE; | ||
180 | fclose(b->file); | ||
181 | b->file = NULL; | ||
182 | return EINA_FALSE; | ||
183 | } | ||
184 | |||
185 | /* copy the type */ | ||
186 | b->type[0] = b->buffer[0]; | ||
187 | b->type[1] = b->buffer[1]; | ||
188 | b->type[2] = 0; | ||
189 | /* skip the PX */ | ||
190 | b->current = b->buffer + 2; | ||
191 | |||
192 | *error = EVAS_LOAD_ERROR_NONE; | ||
193 | return EINA_TRUE; | ||
194 | } | ||
195 | |||
196 | static void | ||
197 | pmaps_buffer_close(Pmaps_Buffer *b) | ||
198 | { | ||
199 | if (b->file) | ||
200 | fclose(b->file); | ||
201 | } | ||
202 | |||
203 | static Eina_Bool | ||
204 | pmaps_buffer_header_parse(Pmaps_Buffer *b, int *error) | ||
205 | { | ||
206 | /* if there is no P at the beginning it is not a file we can parse */ | ||
207 | if (b->type[0] != 'P') | ||
208 | { | ||
209 | *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; | ||
210 | return EINA_FALSE; | ||
211 | } | ||
212 | |||
213 | /* get the width */ | ||
214 | if (!pmaps_buffer_plain_int_get(b, &(b->w)) || b->w < 1) | ||
215 | { | ||
216 | *error = EVAS_LOAD_ERROR_CORRUPT_FILE; | ||
217 | return EINA_FALSE; | ||
218 | } | ||
219 | |||
220 | /* get the height */ | ||
221 | if (!pmaps_buffer_plain_int_get(b, &(b->h)) || b->h < 1) | ||
222 | { | ||
223 | *error = EVAS_LOAD_ERROR_CORRUPT_FILE; | ||
224 | return EINA_FALSE; | ||
225 | } | ||
226 | |||
227 | /* get the maximum value. P1 and P4 don't have a maximum value. */ | ||
228 | if (!(b->type[1] == '1' || b->type[1] == '4') | ||
229 | && (!pmaps_buffer_plain_int_get(b, &(b->max)) || b->max < 1)) | ||
230 | { | ||
231 | *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT; | ||
232 | return EINA_FALSE; | ||
233 | } | ||
234 | |||
235 | /* set up the color get callback */ | ||
236 | switch (b->type[1]) | ||
237 | { | ||
238 | /* Black and White */ | ||
239 | case '1': | ||
240 | b->color_get = pmaps_buffer_plain_bw_get; | ||
241 | break; | ||
242 | case '4': | ||
243 | /* Binary black and white use another format */ | ||
244 | b->color_get = NULL; | ||
245 | break; | ||
246 | case '2': | ||
247 | case '5': | ||
248 | b->color_get = pmaps_buffer_gray_get; | ||
249 | break; | ||
250 | case '3': | ||
251 | case '6': | ||
252 | b->color_get = pmaps_buffer_rgb_get; | ||
253 | break; | ||
254 | case '7': | ||
255 | /* XXX write me */ | ||
256 | return 0; | ||
257 | break; | ||
258 | default: | ||
259 | return 0; | ||
260 | } | ||
261 | /* set up the int get callback */ | ||
262 | switch (b->type[1]) | ||
263 | { | ||
264 | /* RAW */ | ||
265 | case '5': | ||
266 | case '6': | ||
267 | if (b->max < 256) | ||
268 | b->int_get = pmaps_buffer_1byte_int_get; | ||
269 | else | ||
270 | b->int_get = pmaps_buffer_2byte_int_get; | ||
271 | |||
272 | if (b->current == b->end && !pmaps_buffer_raw_update(b)) | ||
273 | return 0; | ||
274 | |||
275 | b->current++; | ||
276 | break; | ||
277 | /* Plain */ | ||
278 | case '2': | ||
279 | case '3': | ||
280 | b->int_get = pmaps_buffer_plain_int_get; | ||
281 | break; | ||
282 | /* Black and White Bitmaps don't use that callback */ | ||
283 | case '1': | ||
284 | case '4': | ||
285 | b->int_get = NULL; | ||
286 | /* we need to skip the next character fpr P4 it | ||
287 | * doesn't hurt if we do it for the P1 as well */ | ||
288 | b->current++; | ||
289 | break; | ||
290 | } | ||
291 | return 1; | ||
292 | } | ||
293 | |||
294 | static size_t | ||
295 | pmaps_buffer_plain_update(Pmaps_Buffer *b) | ||
296 | { | ||
297 | size_t r; | ||
298 | |||
299 | /* if we already are in the last buffer we can not update it */ | ||
300 | if (b->last_buffer) | ||
301 | return 0; | ||
302 | |||
303 | /* if we have unread bytes we need to put them before the new read | ||
304 | * stuff */ | ||
305 | if (b->unread_len) | ||
306 | memcpy(b->buffer, b->unread, b->unread_len); | ||
307 | |||
308 | r = fread(&b->buffer[b->unread_len], 1, | ||
309 | FILE_BUFFER_SIZE - b->unread_len - 1, b->file) + b->unread_len; | ||
310 | |||
311 | /* we haven't read anything nor have we bytes in the unread buffer */ | ||
312 | if (r == 0) | ||
313 | { | ||
314 | b->buffer[0] = '\0'; | ||
315 | b->end = b->buffer; | ||
316 | b->last_buffer = 1; | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | if (r < FILE_BUFFER_SIZE - 1) | ||
321 | { | ||
322 | /*we reached eof */ ; | ||
323 | b->last_buffer = 1; | ||
324 | } | ||
325 | |||
326 | b->buffer[r] = 0; | ||
327 | |||
328 | b->unread[0] = '\0'; | ||
329 | b->unread_len = 0; | ||
330 | |||
331 | b->buffer[r] = '\0'; | ||
332 | b->current = b->buffer; | ||
333 | b->end = b->buffer + r; | ||
334 | |||
335 | return r; | ||
336 | } | ||
337 | |||
338 | static size_t | ||
339 | pmaps_buffer_raw_update(Pmaps_Buffer *b) | ||
340 | { | ||
341 | size_t r; | ||
342 | |||
343 | if (b->last_buffer) | ||
344 | return 0; | ||
345 | |||
346 | if (b->unread_len) | ||
347 | memcpy(b->buffer, b->unread, b->unread_len); | ||
348 | |||
349 | r = fread(&b->buffer[b->unread_len], 1, FILE_BUFFER_SIZE - b->unread_len, | ||
350 | b->file) + b->unread_len; | ||
351 | |||
352 | if (r < FILE_BUFFER_SIZE) | ||
353 | { | ||
354 | /*we reached eof */ | ||
355 | b->last_buffer = 1; | ||
356 | } | ||
357 | |||
358 | b->end = b->buffer + r; | ||
359 | b->current = b->buffer; | ||
360 | |||
361 | if (b->unread_len) | ||
362 | { | ||
363 | /* the buffer is now read */ | ||
364 | *b->unread = 0; | ||
365 | b->unread_len = 0; | ||
366 | } | ||
367 | |||
368 | return r; | ||
369 | } | ||
370 | |||
371 | static int | ||
372 | pmaps_buffer_plain_int_get(Pmaps_Buffer *b, int *val) | ||
373 | { | ||
374 | char *start; | ||
375 | DATA8 lastc; | ||
376 | |||
377 | /* first skip all white space | ||
378 | * Note: we are skipping here actually every character than is not | ||
379 | * a digit */ | ||
380 | while (!isdigit(*b->current)) | ||
381 | { | ||
382 | if (*b->current == '\0') | ||
383 | { | ||
384 | if (!pmaps_buffer_plain_update(b)) | ||
385 | return 0; | ||
386 | |||
387 | continue; | ||
388 | } | ||
389 | if (*b->current == '#' && !pmaps_buffer_comment_skip(b)) | ||
390 | return 0; | ||
391 | b->current++; | ||
392 | } | ||
393 | |||
394 | start = (char *)b->current; | ||
395 | /* now find the end of the number */ | ||
396 | while (isdigit(*b->current)) | ||
397 | b->current++; | ||
398 | |||
399 | lastc = *b->current; | ||
400 | *b->current = '\0'; | ||
401 | *val = atoi(start); | ||
402 | *b->current = lastc; | ||
403 | |||
404 | return 1; | ||
405 | } | ||
406 | |||
407 | static int | ||
408 | pmaps_buffer_1byte_int_get(Pmaps_Buffer *b, int *val) | ||
409 | { | ||
410 | /* are we at the end of the buffer? */ | ||
411 | if (b->current == b->end && !pmaps_buffer_raw_update(b)) | ||
412 | return 0; | ||
413 | |||
414 | *val = *b->current; | ||
415 | b->current++; | ||
416 | |||
417 | return 1; | ||
418 | } | ||
419 | static int | ||
420 | pmaps_buffer_2byte_int_get(Pmaps_Buffer *b, int *val) | ||
421 | { | ||
422 | /* are we at the end of the buffer? */ | ||
423 | if (b->current == b->end && !pmaps_buffer_raw_update(b)) | ||
424 | return 0; | ||
425 | |||
426 | *val = (int)(*b->current << 8); | ||
427 | b->current++; | ||
428 | |||
429 | /* are we at the end of the buffer? */ | ||
430 | if (b->current == b->end && !pmaps_buffer_raw_update(b)) | ||
431 | return 0; | ||
432 | |||
433 | *val |= *b->current; | ||
434 | b->current++; | ||
435 | |||
436 | return 1; | ||
437 | } | ||
438 | |||
439 | static int | ||
440 | pmaps_buffer_comment_skip(Pmaps_Buffer *b) | ||
441 | { | ||
442 | while (*b->current != '\n') | ||
443 | { | ||
444 | if (*b->current == '\0') | ||
445 | { | ||
446 | if (!pmaps_buffer_plain_update(b)) | ||
447 | return 0; | ||
448 | |||
449 | continue; | ||
450 | } | ||
451 | b->current++; | ||
452 | } | ||
453 | return 1; | ||
454 | } | ||
455 | |||
456 | static int | ||
457 | pmaps_buffer_rgb_get(Pmaps_Buffer *b, DATA32 *color) | ||
458 | { | ||
459 | int vr, vg, vb; | ||
460 | |||
461 | if (!b->int_get(b, &vr) || !b->int_get(b, &vg) || !b->int_get(b, &vb)) | ||
462 | return 0; | ||
463 | |||
464 | if (b->max != 255) | ||
465 | { | ||
466 | vr = (vr * 255) / b->max; | ||
467 | vg = (vg * 255) / b->max; | ||
468 | vb = (vb * 255) / b->max; | ||
469 | } | ||
470 | if (vr > 255) | ||
471 | vr = 255; | ||
472 | if (vg > 255) | ||
473 | vg = 255; | ||
474 | if (vb > 255) | ||
475 | vb = 255; | ||
476 | |||
477 | *color = ARGB_JOIN(0xff, vr, vg, vb); | ||
478 | |||
479 | return 1; | ||
480 | } | ||
481 | |||
482 | static int | ||
483 | pmaps_buffer_gray_get(Pmaps_Buffer *b, DATA32 *color) | ||
484 | { | ||
485 | int val; | ||
486 | |||
487 | if (!b->int_get(b, &val)) | ||
488 | return 0; | ||
489 | |||
490 | if (b->max != 255) | ||
491 | val = (val * 255) / b->max; | ||
492 | if (val > 255) | ||
493 | val = 255; | ||
494 | *color = ARGB_JOIN(0xff, val, val, val); | ||
495 | |||
496 | return 1; | ||
497 | } | ||
498 | |||
499 | static int | ||
500 | pmaps_buffer_plain_bw_get(Pmaps_Buffer *b, DATA32 *val) | ||
501 | { | ||
502 | /* first skip all white space | ||
503 | * Note: we are skipping here actually every character than is not | ||
504 | * a digit */ | ||
505 | while (!isdigit(*b->current)) | ||
506 | { | ||
507 | if (*b->current == '\0') | ||
508 | { | ||
509 | if (!pmaps_buffer_raw_update(b)) | ||
510 | return 0; | ||
511 | |||
512 | continue; | ||
513 | } | ||
514 | if (*b->current == '#' && !pmaps_buffer_comment_skip(b)) | ||
515 | return 0; | ||
516 | b->current++; | ||
517 | } | ||
518 | |||
519 | if (*b->current == '0') | ||
520 | *val = 0xffffffff; | ||
521 | else | ||
522 | *val = 0xff000000; | ||
523 | |||
524 | b->current++; | ||
525 | |||
526 | return 1; | ||
527 | } | ||
528 | |||
529 | /* external functions */ | ||
530 | static int | ||
531 | module_open(Evas_Module *em) | ||
532 | { | ||
533 | if (!em) | ||
534 | return 0; | ||
535 | em->functions = (void *)(&evas_image_load_pmaps_func); | ||
536 | return 1; | ||
537 | } | ||
538 | |||
539 | static void | ||
540 | module_close(Evas_Module *em __UNUSED__) | ||
541 | { | ||
542 | } | ||
543 | |||
544 | static Evas_Module_Api evas_modapi = { | ||
545 | EVAS_MODULE_API_VERSION, | ||
546 | "pmaps", | ||
547 | "none", | ||
548 | { | ||
549 | module_open, | ||
550 | module_close | ||
551 | } | ||
552 | }; | ||
553 | |||
554 | EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, pmaps); | ||
555 | |||
556 | #ifndef EVAS_STATIC_BUILD_PMAPS | ||
557 | EVAS_EINA_MODULE_DEFINE(image_loader, pmaps); | ||
558 | #endif | ||