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