move around - flatter.
[profile/ivi/evas.git] / src / modules / loaders / xpm / evas_image_load_xpm.c
1 #include "evas_common.h"
2 #include "evas_private.h"
3
4 int evas_image_load_file_head_xpm(Image_Entry *ie, const char *file, const char *key);
5 int evas_image_load_file_data_xpm(Image_Entry *ie, const char *file, const char *key);
6
7 Evas_Image_Load_Func evas_image_load_xpm_func =
8 {
9   evas_image_load_file_head_xpm,
10   evas_image_load_file_data_xpm
11 };
12
13
14 static FILE *rgb_txt = NULL;
15
16 static void
17 xpm_parse_color(char *color, int *r, int *g, int *b)
18 {
19    char                buf[4096];
20
21    /* is a #ff00ff like color */
22    if (color[0] == '#')
23      {
24         int                 len;
25         char                val[32];
26         
27         len = strlen(color) - 1;
28         if (len < 96)
29           {
30              int                 i;
31              
32              len /= 3;
33              for (i = 0; i < len; i++)
34                 val[i] = color[1 + i + (0 * len)];
35              val[i] = 0;
36              sscanf(val, "%x", r);
37              for (i = 0; i < len; i++)
38                 val[i] = color[1 + i + (1 * len)];
39              val[i] = 0;
40              sscanf(val, "%x", g);
41              for (i = 0; i < len; i++)
42                 val[i] = color[1 + i + (2 * len)];
43              val[i] = 0;
44              sscanf(val, "%x", b);
45              if (len == 1)
46                {
47                   *r = (*r << 4) | *r;
48                   *g = (*g << 4) | *g;
49                   *b = (*b << 4) | *b;
50                }
51              else if (len > 2)
52                {
53                   *r >>= (len - 2) * 4;
54                   *g >>= (len - 2) * 4;
55                   *b >>= (len - 2) * 4;
56                }
57           }
58         return;
59      }
60    /* look in rgb txt database */
61    if (!rgb_txt) rgb_txt = fopen("/usr/lib/X11/rgb.txt", "r");
62    if (!rgb_txt) rgb_txt = fopen("/usr/X11/lib/X11/rgb.txt", "r");
63    if (!rgb_txt) rgb_txt = fopen("/usr/X11R6/lib/X11/rgb.txt", "r");
64    if (!rgb_txt) rgb_txt = fopen("/usr/openwin/lib/X11/rgb.txt", "r");
65    if (!rgb_txt) return;
66    fseek(rgb_txt, 0, SEEK_SET);
67    while (fgets(buf, sizeof(buf), rgb_txt))
68      {
69         buf[sizeof(buf) - 1] = 0;
70         if (buf[0] != '!')
71           {
72              int rr, gg, bb;
73              char name[4096];
74              
75              if (sscanf(buf, "%i %i %i %[^\n]", &rr, &gg, &bb, name) == 4)
76                {
77                   if (!strcasecmp(name, color))
78                     {
79                        *r = rr;
80                        *g = gg;
81                        *b = bb;
82                        return;
83                     }
84                }
85           }
86      }
87 }
88
89 static void
90 xpm_parse_done(void)
91 {
92    if (rgb_txt) fclose(rgb_txt);
93    rgb_txt = NULL;
94 }
95
96
97 /** FIXME: clean this up and make more efficient  **/
98 static int
99 evas_image_load_file_xpm(Image_Entry *ie, const char *file, const char *key, int load_data)
100 {
101    DATA32             *ptr, *end;
102    FILE               *f;
103
104    int                 pc, c, i, j, k, w, h, ncolors, cpp, comment, transp,
105                        quote, context, len, done, r, g, b, backslash, lu1, lu2;
106    char               *line, s[256], tok[128], col[256], *tl;
107    int                 lsz = 256;
108    struct _cmap {
109       unsigned char    str[6];
110       unsigned char    transp;
111       short            r, g, b;
112    }                  *cmap;
113
114    short               lookup[128 - 32][128 - 32];
115    int                 count, pixels;
116
117    if (!file) return 0;
118    done = 0;
119 //   transp = -1;
120    transp = 1;
121
122    /* if immediate_load is 1, then dont delay image laoding as below, or */
123    /* already data in this image - dont load it again */
124
125    f = fopen(file, "rb");
126    if (!f)
127      {
128         xpm_parse_done();
129         return 0;
130      }
131    if (fread(s, 9, 1, f) != 1)
132      {
133         fclose(f);
134         xpm_parse_done();
135         return 0;
136      }
137    rewind(f);
138    s[9] = 0;
139    if (strcmp("/* XPM */", s))
140      {
141         fclose(f);
142         xpm_parse_done();
143         return 0;
144      }
145    
146    i = 0;
147    j = 0;
148    cmap = NULL;
149    w = 10;
150    h = 10;
151    ptr = NULL;
152    end = NULL;
153    c = ' ';
154    comment = 0;
155    quote = 0;
156    context = 0;
157    pixels = 0;
158    count = 0;
159    line = malloc(lsz);
160    if (!line)
161      {
162         fclose(f);
163         xpm_parse_done();
164         return 0;
165      }
166
167    backslash = 0;
168    memset(lookup, 0, sizeof(lookup));
169    while (!done)
170      {
171         pc = c;
172         c = fgetc(f);
173         if (c == EOF) break;
174         if (!quote)
175           {
176              if ((pc == '/') && (c == '*'))
177                comment = 1;
178              else if ((pc == '*') && (c == '/') && (comment))
179                comment = 0;
180           }
181         if (!comment)
182           {
183              if ((!quote) && (c == '"'))
184                {
185                   quote = 1;
186                   i = 0;
187                }
188              else if ((quote) && (c == '"'))
189                {
190                   line[i] = 0;
191                   quote = 0;
192                   if (context == 0)
193                     {
194                        /* Header */
195                        if (sscanf(line, "%i %i %i %i", &w, &h, &ncolors, &cpp) != 4)
196                          {
197                             fprintf(stderr,
198                                     "XPM ERROR: XPM file malformed header\n");
199                             free(line);
200                             fclose(f);
201                             xpm_parse_done();
202                             return 0;
203                          }
204                        if ((ncolors > 32766) || (ncolors < 1))
205                          {
206                             fprintf(stderr,
207                                     "XPM ERROR: XPM files with colors > 32766 or < 1 not supported\n");
208                             free(line);
209                             fclose(f);
210                             xpm_parse_done();
211                             return 0;
212                          }
213                        if ((cpp > 5) || (cpp < 1))
214                          {
215                             fprintf(stderr,
216                                     "XPM ERROR: XPM files with characters per pixel > 5 or < 1not supported\n");
217                             free(line);
218                             fclose(f);
219                             xpm_parse_done();
220                             return 0;
221                          }
222                        if ((w > 8192) || (w < 1))
223                          {
224                             fprintf(stderr,
225                                     "XPM ERROR: Image width > 8192 or < 1 pixels for file\n");
226                             free(line);
227                             fclose(f);
228                             xpm_parse_done();
229                             return 0;
230                          }
231                        if ((h > 8192) || (h < 1))
232                          {
233                             fprintf(stderr,
234                                     "XPM ERROR: Image height > 8192 or < 1 pixels for file\n");
235                             free(line);
236                             fclose(f);
237                             xpm_parse_done();
238                             return 0;
239                          }
240
241                        if (!cmap)
242                          {
243                             cmap = malloc(sizeof(struct _cmap) * ncolors);
244                             if (!cmap)
245                               {
246                                 free(line);
247                                 fclose(f);
248                                 xpm_parse_done();
249                                 return 0;
250                               }
251                          }
252                        ie->w = w;
253                        ie->h = h;
254
255                        j = 0;
256                        context++;
257                     }
258                   else if (context == 1)
259                     {
260                        /* Color Table */
261                        if (j < ncolors)
262                          {
263                             int                 slen;
264                             int                 hascolor, iscolor;
265
266                             iscolor = 0;
267                             hascolor = 0;
268                             tok[0] = 0;
269                             col[0] = 0;
270                             s[0] = 0;
271                             len = strlen(line);
272                             strncpy(cmap[j].str, line, cpp);
273                             cmap[j].str[cpp] = 0;
274                             for (slen = 0; slen < cpp; slen++)
275                               {
276                                  /* fix the ascii of the  color string - if its < 32 - just limit to 32 */
277                                  if (cmap[j].str[slen] < 32) cmap[j].str[slen] = 0;
278                               }
279                             cmap[j].r = -1;
280                             cmap[j].transp = 0;
281                             for (k = cpp; k < len; k++)
282                               {
283                                  if (line[k] != ' ')
284                                    {
285                                       s[0] = 0;
286                                       sscanf(&line[k], "%255s", s);
287                                       slen = strlen(s);
288                                       k += slen;
289                                       if (!strcmp(s, "c")) iscolor = 1;
290                                       if ((!strcmp(s, "m")) || (!strcmp(s, "s"))
291                                           || (!strcmp(s, "g4")) || (!strcmp(s, "g"))
292                                           || (!strcmp(s, "c")) || (k >= len))
293                                         {
294                                            if (k >= len)
295                                              {
296                                                 if (col[0])
297                                                   {
298                                                      if (strlen(col) < (sizeof(col) - 2))
299                                                        strcat(col, " ");
300                                                      else
301                                                        done = 1;
302                                                   }
303                                                 if ((strlen(col) + strlen(s)) < (sizeof(col) - 1))
304                                                   strcat(col, s);
305                                              }
306                                            if (col[0])
307                                              {
308                                                 if (!strcasecmp(col, "none"))
309                                                   {
310                                                      transp = 1;
311                                                      cmap[j].transp = 1;
312                                                      cmap[j].r = 0;
313                                                      cmap[j].g = 0;
314                                                      cmap[j].b = 0;
315                                                   }
316                                                 else
317                                                   {
318                                                      if ((((cmap[j].r < 0) || (!strcmp(tok, "c"))) && (!hascolor)))
319                                                        {
320                                                           r = g = b = 0;
321                                                           xpm_parse_color(col, &r, &g, &b);
322                                                           cmap[j].r = r;
323                                                           cmap[j].g = g;
324                                                           cmap[j].b = b;
325                                                           if (iscolor) hascolor = 1;
326                                                        }
327                                                   }
328                                              }
329                                            strcpy(tok, s);
330                                            col[0] = 0;
331                                         }
332                                       else
333                                         {
334                                            if (col[0])
335                                              {
336                                                 if (strlen(col) < ( sizeof(col) - 2))
337                                                   strcat(col, " ");
338                                                 else
339                                                   done = 1;
340                                              }
341                                            if ((strlen(col) + strlen(s)) < (sizeof(col) - 1))
342                                              strcat(col, s);
343                                         }
344                                    }
345                               }
346                          }
347                        j++;
348                        if (j >= ncolors)
349                          {
350                             if (cpp == 1)
351                               {
352                                  for (i = 0; i < ncolors; i++)
353                                    lookup[(int)cmap[i].str[0] - 32][0] = i;
354                               }
355                             if (cpp == 2)
356                               {
357                                  for (i = 0; i < ncolors; i++)
358                                    lookup[(int)cmap[i].str[0] - 32][(int)cmap[i].str[1] - 32] = i;
359                               }
360                             context++;
361                          }
362
363                        if (transp) ie->flags.alpha = 1;
364                        
365                        if (load_data)
366                          {
367                             evas_cache_image_surface_alloc(ie, w, h);
368                             ptr = evas_cache_image_pixels(ie);
369                             if (!ptr)
370                               {
371                                  free(cmap);
372                                  free(line);
373                                  fclose(f);
374                                  xpm_parse_done();
375                                  return 0;
376                               }
377                             end = ptr + (w * h);
378                             pixels = w * h;
379                          }
380                        else
381                          {
382                             free(cmap);
383                             free(line);
384                             fclose(f);
385                             xpm_parse_done();
386                             return 1;
387                          }
388                     }
389                   else
390                     {
391                        /* Image Data */
392                        i = 0;
393                        if (cpp == 0)
394                          {
395                             /* Chars per pixel = 0? well u never know */
396                          }
397                        /* it's xpm - don't care about speed too much. still faster
398                         * that most xpm loaders anyway */
399                        else if (cpp == 1)
400                          {
401                             if (transp)
402                               {
403                                  for (i = 0;
404                                       ((i < 65536) && (ptr < end) && (line[i]));
405                                       i++)
406                                    {
407                                       lu1 = (int)line[i] - 32;
408                                       if (lu1 < 0) continue;
409                                       if (cmap[lookup[lu1][0]].transp)
410                                         {
411                                            r = (unsigned char)cmap[lookup[lu1][0]].r;
412                                            g = (unsigned char)cmap[lookup[lu1][0]].g;
413                                            b = (unsigned char)cmap[lookup[lu1][0]].b;
414                                            *ptr = (r << 16) | (g << 8) | b;
415                                            ptr++;
416                                            count++;
417                                         }
418                                       else
419                                         {
420                                            r = (unsigned char)cmap[lookup[lu1][0]].r;
421                                            g = (unsigned char)cmap[lookup[lu1][0]].g;
422                                            b = (unsigned char)cmap[lookup[lu1][0]].b;
423                                            *ptr = (0xff << 24) | (r << 16) | (g << 8) | b;
424                                            ptr++;
425                                            count++;
426                                         }
427                                    }
428                               }
429                             else
430                               {
431                                  for (i = 0;
432                                       ((i < 65536) && (ptr < end) && (line[i]));
433                                       i++)
434                                    {
435                                       lu1 = (int)line[i] - 32;
436                                       if (lu1 < 0) continue;
437                                       r = (unsigned char)cmap[lookup[lu1][0]].r;
438                                       g = (unsigned char)cmap[lookup[lu1][0]].g;
439                                       b = (unsigned char)cmap[lookup[lu1][0]].b;
440                                       *ptr = (0xff << 24) | (r << 16) | (g << 8) | b;
441                                       ptr++;
442                                       count++;
443                                    }
444                               }
445                          }
446                        else if (cpp == 2)
447                          {
448                             if (transp)
449                               {
450                                  for (i = 0;
451                                       ((i < 65536) && (ptr < end) && (line[i]));
452                                       i++)
453                                    {
454                                       lu1 = (int)line[i] - 32;
455                                       i++;
456                                       lu2 = (int)line[i] - 32;
457                                       if (lu1 < 0) continue;
458                                       if (lu2 < 0) continue;
459                                       if (cmap[lookup[lu1][lu2]].transp)
460                                         {
461                                            r = (unsigned char)cmap[lookup[lu1][lu2]].r;
462                                            g = (unsigned char)cmap[lookup[lu1][lu2]].g;
463                                            b = (unsigned char)cmap[lookup[lu1][lu2]].b;
464                                            *ptr = (r << 16) | (g << 8) | b;
465                                            ptr++;
466                                            count++;
467                                         }
468                                       else
469                                         {
470                                            r = (unsigned char)cmap[lookup[lu1][lu2]].r;
471                                            g = (unsigned char)cmap[lookup[lu1][lu2]].g;
472                                            b = (unsigned char)cmap[lookup[lu1][lu2]].b;
473                                            *ptr = (0xff << 24) | (r << 16) | (g << 8) | b;
474                                            ptr++;
475                                            count++;
476                                         }
477                                    }
478                               }
479                             else
480                               {
481                                  for (i = 0;
482                                       ((i < 65536) && (ptr < end) && (line[i]));
483                                       i++)
484                                    {
485                                       lu1 = (int)line[i] - 32;
486                                       i++;
487                                       lu2 = (int)line[i] - 32;
488                                       if (lu1 < 0) continue;
489                                       if (lu2 < 0) continue;
490                                       r = (unsigned char)cmap[lookup[lu1][lu2]].r;
491                                       g = (unsigned char)cmap[lookup[lu1][lu2]].g;
492                                       b = (unsigned char)cmap[lookup[lu1][lu2]].b;
493                                       *ptr = (0xff << 24) | (r << 16) | (g << 8) | b;
494                                       ptr++;
495                                       count++;
496                                    }
497                               }
498                          }
499                        else
500                          {
501                             if (transp)
502                               {
503                                  for (i = 0;
504                                       ((i < 65536) && (ptr < end) && (line[i]));
505                                       i++)
506                                    {
507                                       for (j = 0; j < cpp; j++, i++)
508                                         {
509                                            col[j] = line[i];
510                                            if (col[j] < 32) col[j] = 32;
511                                         }
512                                       col[j] = 0;
513                                       i--;
514                                       for (j = 0; j < ncolors; j++)
515                                         {
516                                            if (!strcmp(col, cmap[j].str))
517                                              {
518                                                 if (cmap[j].transp)
519                                                   {
520                                                      r = (unsigned char)cmap[j].r;
521                                                      g = (unsigned char)cmap[j].g;
522                                                      b = (unsigned char)cmap[j].b;
523                                                      *ptr = (r << 16) | (g << 8) | b;
524                                                      ptr++;
525                                                      count++;
526                                                   }
527                                                 else
528                                                   {
529                                                      r = (unsigned char)cmap[j].r;
530                                                      g = (unsigned char)cmap[j].g;
531                                                      b = (unsigned char)cmap[j].b;
532                                                      *ptr = (0xff << 24) | (r << 16) | (g << 8) | b;
533                                                      ptr++;
534                                                      count++;
535                                                   }
536                                                 break;
537                                              }
538                                         }
539                                    }
540                               }
541                             else
542                               {
543                                  for (i = 0;
544                                       ((i < 65536) && (ptr < end) && (line[i]));
545                                       i++)
546                                    {
547                                       for (j = 0; j < cpp; j++, i++)
548                                         {
549                                            col[j] = line[i];
550                                         }
551                                       col[j] = 0;
552                                       i--;
553                                       for (j = 0; j < ncolors; j++)
554                                         {
555                                            if (!strcmp(col, cmap[j].str))
556                                              {
557                                                 r = (unsigned char)cmap[j].r;
558                                                 g = (unsigned char)cmap[j].g;
559                                                 b = (unsigned char)cmap[j].b;
560                                                 *ptr = (0xff << 24) | (r << 16) | (g << 8) | b;
561                                                 ptr++;
562                                                 count++;
563                                                 break;
564                                              }
565                                         }
566                                    }
567                               }
568                          }
569                     }
570                }
571           }
572         /* Scan in line from XPM file */
573         if ((!comment) && (quote) && (c != '"'))
574           {
575              if (c < 32) c = 32;
576              else if (c > 127) c = 127;
577              if (c =='\\')
578                {
579                   if (++backslash < 2)
580                     line[i++] = c;
581                   else
582                     backslash = 0;
583                }
584              else
585                {
586                   backslash = 0;
587                   line[i++] = c;
588                }
589           }
590         if (i >= lsz)
591           {
592              lsz += 256;
593              tl = realloc(line, lsz);
594              if (!tl) break;
595              line = tl;
596           }
597         if (((ptr) && ((ptr - evas_cache_image_pixels(ie)) >= (w * h * sizeof(DATA32)))) ||
598             ((context > 1) && (count >= pixels)))
599           break;
600      }
601
602    if (cmap) free(cmap);
603    if (line) free(line);
604    if (f) fclose(f);
605
606    xpm_parse_done();
607
608    return 1;
609 }
610
611
612 int
613 evas_image_load_file_head_xpm(Image_Entry *ie, const char *file, const char *key)
614 {
615   return evas_image_load_file_xpm(ie, file, key, 0);
616 }
617
618 int
619 evas_image_load_file_data_xpm(Image_Entry *ie, const char *file, const char *key)
620 {
621   return evas_image_load_file_xpm(ie, file, key, 1);
622 }
623
624
625
626 EAPI int
627 module_open(Evas_Module *em)
628 {
629    if (!em) return 0;
630    em->functions = (void *)(&evas_image_load_xpm_func);
631    return 1;
632 }
633
634 EAPI void
635 module_close(void)
636 {
637    
638 }
639
640 EAPI Evas_Module_Api evas_modapi =
641 {
642    EVAS_MODULE_API_VERSION,
643      EVAS_MODULE_TYPE_IMAGE_LOADER,
644      "xpm",
645      "none"
646 };