1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4 
5 #include <stdio.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 
9 #include "evas_common_private.h"
10 #include "evas_private.h"
11 
12 /* TGA pixel formats */
13 #define TGA_TYPE_MAPPED      1 // handle
14 #define TGA_TYPE_COLOR       2
15 #define TGA_TYPE_GRAY        3
16 #define TGA_TYPE_MAPPED_RLE  9 // handle
17 #define TGA_TYPE_COLOR_RLE  10
18 #define TGA_TYPE_GRAY_RLE   11
19 
20 /* TGA header flags */
21 #define TGA_DESC_ABITS      0x0f
22 #define TGA_DESC_HORIZONTAL 0x10
23 #define TGA_DESC_VERTICAL   0x20
24 
25 #define TGA_SIGNATURE "TRUEVISION-XFILE"
26 
27 typedef struct _tga_header tga_header;
28 typedef struct _tga_footer tga_footer;
29 
30 struct _tga_header
31 {
32    unsigned char       idLength;
33    unsigned char       colorMapType;
34    unsigned char       imageType;
35    unsigned char       colorMapIndexLo, colorMapIndexHi;
36    unsigned char       colorMapLengthLo, colorMapLengthHi;
37    unsigned char       colorMapSize;
38    unsigned char       xOriginLo, xOriginHi;
39    unsigned char       yOriginLo, yOriginHi;
40    unsigned char       widthLo, widthHi;
41    unsigned char       heightLo, heightHi;
42    unsigned char       bpp;
43    unsigned char       descriptor;
44 } __attribute__((packed));
45 
46 struct _tga_footer
47 {
48    unsigned int        extensionAreaOffset;
49    unsigned int        developerDirectoryOffset;
50    char                signature[16];
51    char                dot;
52    char                null;
53 } __attribute__((packed));
54 
55 static void *
evas_image_load_file_open_tga(Eina_File * f,Eina_Stringshare * key EINA_UNUSED,Evas_Image_Load_Opts * opts EINA_UNUSED,Evas_Image_Animated * animated EINA_UNUSED,int * error EINA_UNUSED)56 evas_image_load_file_open_tga(Eina_File *f, Eina_Stringshare *key EINA_UNUSED,
57                               Evas_Image_Load_Opts *opts EINA_UNUSED,
58                               Evas_Image_Animated *animated EINA_UNUSED,
59                               int *error EINA_UNUSED)
60 {
61    return f;
62 }
63 
64 static void
evas_image_load_file_close_tga(void * loader_data EINA_UNUSED)65 evas_image_load_file_close_tga(void *loader_data EINA_UNUSED)
66 {
67 }
68 
69 static Eina_Bool
evas_image_load_file_head_tga(void * loader_data,Emile_Image_Property * prop,int * error)70 evas_image_load_file_head_tga(void *loader_data,
71                               Emile_Image_Property *prop,
72                               int *error)
73 {
74    Eina_File *f = loader_data;
75    unsigned char *seg = NULL, *filedata;
76    tga_header *header;
77    tga_footer *footer, tfooter;
78    char hasa = 0;
79    int w, h, bpp;
80    int x, y;
81    Eina_Bool r = EINA_FALSE;
82 
83    *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
84    if (eina_file_size_get(f) < (off_t)(sizeof(tga_header) + sizeof(tga_footer)))
85       goto close_file;
86    seg = eina_file_map_all(f, EINA_FILE_RANDOM);
87    if (seg == NULL) goto close_file;
88    filedata = seg;
89 
90    header = (tga_header *)filedata;
91    // no unaligned data accessed, so ok
92    footer = (tga_footer *)(filedata + (eina_file_size_get(f) - sizeof(tga_footer)));
93    memcpy((unsigned char *)(&tfooter),
94           (unsigned char *)footer,
95           sizeof(tga_footer));
96    //printf("0\n");
97    if (!memcmp(tfooter.signature, TGA_SIGNATURE, sizeof(tfooter.signature)))
98      {
99         if ((tfooter.dot == '.') && (tfooter.null == 0))
100           {
101              // footer is there and matches. this is a tga file - any problems now
102              // are a corrupt file
103              *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
104           }
105      }
106 //   else goto close_file;
107    //printf("1\n");
108 
109    filedata = (unsigned char *)filedata + sizeof(tga_header);
110    switch (header->imageType)
111      {
112      case TGA_TYPE_COLOR_RLE:
113      case TGA_TYPE_GRAY_RLE:
114 //        rle = 1;
115         break;
116      case TGA_TYPE_COLOR:
117      case TGA_TYPE_GRAY:
118 //        rle = 0;
119         break;
120      default:
121         goto close_file;
122      }
123    bpp = header->bpp;
124    if (!((bpp == 32) || (bpp == 24) || (bpp == 16) || (bpp == 8)))
125      goto close_file;
126    if ((bpp == 32) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
127    if ((bpp == 16) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
128    // don't handle colormapped images
129    if ((header->colorMapType) != 0)
130      goto close_file;
131    // if colormap size is anything other than legal sizes or 0 - not real tga
132    if (!((header->colorMapSize == 0) ||
133          (header->colorMapSize == 15) ||
134          (header->colorMapSize == 16) ||
135          (header->colorMapSize == 24) ||
136          (header->colorMapSize == 32)))
137      goto close_file;
138    x = (header->xOriginHi << 8) | (header->xOriginLo);
139    y = (header->yOriginHi << 8) | (header->yOriginLo);
140    w = (header->widthHi << 8) | header->widthLo;
141    h = (header->heightHi << 8) | header->heightLo;
142    // x origin gerater that width, y origin greater than height - wrong file
143    if ((x >= w) || (y >= h))
144      goto close_file;
145    // if descriptor has either of the top 2 bits set... not tga
146    if (header->descriptor & 0xc0)
147      goto close_file;
148 
149    if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
150        IMG_TOO_BIG(w, h))
151      goto close_file;
152 
153    prop->w = w;
154    prop->h = h;
155    if (hasa) prop->alpha = 1;
156 
157    *error = EVAS_LOAD_ERROR_NONE;
158    r = EINA_TRUE;
159 
160 close_file:
161    if (seg != NULL) eina_file_map_free(f, seg);
162    return r;
163 }
164 
165 static Eina_Bool
evas_image_load_file_data_tga(void * loader_data,Emile_Image_Property * prop,void * pixels,int * error)166 evas_image_load_file_data_tga(void *loader_data,
167                               Emile_Image_Property *prop,
168                               void *pixels,
169                               int *error)
170 {
171    Eina_File *f = loader_data;
172    unsigned char *seg = NULL, *filedata;
173    tga_header *header;
174    tga_footer *footer, tfooter;
175    char hasa = 0, footer_present = 0, vinverted = 0, rle = 0;
176    int w = 0, h = 0, x, y, bpp;
177    off_t size;
178    unsigned int *surface, *dataptr;
179    unsigned int  datasize;
180    unsigned char *bufptr, *bufend;
181    int abits;
182    Eina_Bool res = EINA_FALSE;
183 
184    *error = EVAS_LOAD_ERROR_UNKNOWN_FORMAT;
185    if (eina_file_size_get(f) < (off_t)(sizeof(tga_header) + sizeof(tga_footer)))
186       goto close_file;
187    seg = eina_file_map_all(f, EINA_FILE_SEQUENTIAL);
188    if (seg == NULL) goto close_file;
189    filedata = seg;
190    size = eina_file_size_get(f);
191 
192    header = (tga_header *)filedata;
193    // no unaligned data accessed, so ok
194    footer = (tga_footer *)(filedata + (size - sizeof(tga_footer)));
195    memcpy((unsigned char *)&tfooter,
196           (unsigned char *)footer,
197           sizeof(tga_footer));
198    if (!memcmp(tfooter.signature, TGA_SIGNATURE, sizeof(tfooter.signature)))
199      {
200         if ((tfooter.dot == '.') && (tfooter.null == 0))
201           {
202              // footer is there and matches. this is a tga file - any problems now
203              // are a corrupt file
204              *error = EVAS_LOAD_ERROR_CORRUPT_FILE;
205              footer_present = 1;
206           }
207      }
208 
209    filedata = (unsigned char *)filedata + sizeof(tga_header);
210    vinverted = !(header->descriptor & TGA_DESC_VERTICAL);
211    switch (header->imageType)
212      {
213      case TGA_TYPE_COLOR_RLE:
214      case TGA_TYPE_GRAY_RLE:
215         rle = 1;
216         break;
217      case TGA_TYPE_COLOR:
218      case TGA_TYPE_GRAY:
219         rle = 0;
220         break;
221      default:
222         goto close_file;
223      }
224    bpp = header->bpp;
225    if (!((bpp == 32) || (bpp == 24) || (bpp == 16) || (bpp == 8)))
226      goto close_file;
227    if ((bpp == 32) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
228    if ((bpp == 16) && (header->descriptor & TGA_DESC_ABITS)) hasa = 1;
229    abits = header->descriptor & TGA_DESC_ABITS;
230    // don't handle colormapped images
231    if ((header->colorMapType) != 0)
232      goto close_file;
233    // if colormap size is anything other than legal sizes or 0 - not real tga
234    if (!((header->colorMapSize == 0) ||
235          (header->colorMapSize == 15) ||
236          (header->colorMapSize == 16) ||
237          (header->colorMapSize == 24) ||
238          (header->colorMapSize == 32)))
239      goto close_file;
240    x = (header->xOriginHi << 8) | (header->xOriginLo);
241    y = (header->yOriginHi << 8) | (header->yOriginLo);
242    w = (header->widthHi << 8) | header->widthLo;
243    h = (header->heightHi << 8) | header->heightLo;
244    // x origin gerater that width, y origin greater than height - wrong file
245    if ((x >= w) || (y >= h))
246      goto close_file;
247    // if descriptor has either of the top 2 bits set... not tga
248    if (header->descriptor & 0xc0)
249      goto close_file;
250 
251    if ((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE) ||
252        IMG_TOO_BIG(w, h))
253      goto close_file;
254 
255    if ((w != (int)prop->w) || (h != (int)prop->h))
256      {
257         *error = EVAS_LOAD_ERROR_GENERIC;
258         goto close_file;
259      }
260    surface = pixels;
261 
262    datasize = size - sizeof(tga_header) - header->idLength;
263    if (footer_present)
264      datasize -= sizeof(tga_footer);
265 
266    bufptr = filedata + header->idLength;
267    bufend = filedata + datasize;
268 
269    if (!rle)
270      {
271         for (y = 0; y < h; y++)
272           {
273              if (vinverted)
274                /* some TGA's are stored upside-down! */
275                dataptr = surface + ((h - y - 1) * w);
276              else
277                dataptr = surface + (y * w);
278              switch (bpp)
279                {
280                case 32:
281                   for (x = 0; (x < w) && ((bufptr + 4) <= bufend); x++)
282                     {
283                        if (hasa)
284                          {
285                             int a = bufptr[3];
286 
287                             switch (abits)
288                               {
289                                case 1:
290                                  a = (a << 7) | (a << 6) | (a << 5) | (a << 4) | (a << 3) | (a << 2) | (a << 1) | (a);
291                                  EINA_FALLTHROUGH;
292                                case 2:
293                                  a = (a << 6) | (a << 4) | (a << 2) | (a);
294                                  EINA_FALLTHROUGH;
295                                case 3:
296                                  a = (a << 5) | (a << 2) | (a >> 1);
297                                  EINA_FALLTHROUGH;
298                                case 4:
299                                  a = (a << 4) | (a);
300                                  EINA_FALLTHROUGH;
301                                case 5:
302                                  a = (a << 3) | (a >> 2);
303                                  EINA_FALLTHROUGH;
304                                case 6:
305                                  a = (a << 2) | (a >> 4);
306                                  EINA_FALLTHROUGH;
307                                case 7:
308                                  a = (a << 1) | (a >> 6);
309                                  EINA_FALLTHROUGH;
310                                default:
311                                  break;
312                               }
313                             *dataptr = ARGB_JOIN(a, bufptr[2], bufptr[1], bufptr[0]);
314                          }
315                        else
316                          *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
317                        dataptr++;
318                        bufptr += 4;
319                     }
320                   break;
321                case 24:
322                   for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
323                     {
324                        *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
325                        dataptr++;
326                        bufptr += 3;
327                     }
328                   break;
329                case 16:
330                   for (x = 0; (x < w) && ((bufptr + 3) <= bufend); x++)
331                     {
332                        unsigned char r, g, b, a;
333                        unsigned short tmp;
334 
335                        tmp =
336                          (((unsigned short)bufptr[1]) << 8) |
337                          (((unsigned short)bufptr[0]));
338                        r = (tmp >> 7) & 0xf8; r |= r >> 5;
339                        g = (tmp >> 2) & 0xf8; g |= g >> 5;
340                        b = (tmp << 3) & 0xf8; b |= b >> 5;
341                        a = 0xff;
342                        if ((hasa) && (tmp & 0x8000)) a = 0;
343                        *dataptr = ARGB_JOIN(a, r, g, b);
344                        dataptr++;
345                        bufptr += 2;
346                     }
347                   break;
348                case 8:
349                   for (x = 0; (x < w) && ((bufptr + 1) <= bufend); x++)
350                     {
351                        *dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[0], bufptr[0]);
352                        dataptr++;
353                        bufptr += 1;
354                     }
355                   break;
356                default:
357                   break;
358                }
359           }
360      }
361    else
362      {
363         int count, i;
364         unsigned char val;
365         unsigned int *dataend;
366 
367         dataptr = surface;
368         dataend = dataptr + (w * h);
369         while ((bufptr < bufend) && (dataptr < dataend))
370           {
371              val = *bufptr;
372              bufptr++;
373              count = (val & 0x7f) + 1;
374              if (val & 0x80) // rel packet
375                {
376                   switch (bpp)
377                     {
378                     case 32:
379                        if (bufptr < (bufend - 4))
380                          {
381                             unsigned char r, g, b;
382                             int a = bufptr[3];
383 
384                             switch (abits)
385                               {
386                                case 1:
387                                  a = (a << 7) | (a << 6) | (a << 5) | (a << 4) | (a << 3) | (a << 2) | (a << 1) | (a);
388                                  EINA_FALLTHROUGH;
389                                case 2:
390                                  a = (a << 6) | (a << 4) | (a << 2) | (a);
391                                  EINA_FALLTHROUGH;
392                                case 3:
393                                  a = (a << 5) | (a << 2) | (a >> 1);
394                                  EINA_FALLTHROUGH;
395                                case 4:
396                                  a = (a << 4) | (a);
397                                  EINA_FALLTHROUGH;
398                                case 5:
399                                  a = (a << 3) | (a >> 2);
400                                  EINA_FALLTHROUGH;
401                                case 6:
402                                  a = (a << 2) | (a >> 4);
403                                  EINA_FALLTHROUGH;
404                                case 7:
405                                  a = (a << 1) | (a >> 6);
406                                  EINA_FALLTHROUGH;
407                                default:
408                                  break;
409                               }
410                             r = bufptr[2];
411                             g = bufptr[1];
412                             b = bufptr[0];
413                             if (!hasa) a = 0xff;
414                             bufptr += 4;
415                             for (i = 0; (i < count) && (dataptr < dataend); i++)
416                               {
417                                  *dataptr = ARGB_JOIN(a, r, g, b);
418                                  dataptr++;
419                               }
420                          }
421                        break;
422                     case 24:
423                        if (bufptr < (bufend - 3))
424                          {
425                             unsigned char r, g, b;
426 
427                             r = bufptr[2];
428                             g = bufptr[1];
429                             b = bufptr[0];
430                             bufptr += 3;
431                             for (i = 0; (i < count) && (dataptr < dataend); i++)
432                               {
433                                  *dataptr = ARGB_JOIN(0xff, r, g, b);
434                                  dataptr++;
435                               }
436                          }
437                        break;
438                     case 16:
439                        if (bufptr < (bufend - 2))
440                          {
441                             unsigned char r, g, b, a;
442                             unsigned short tmp;
443 
444                             tmp =
445                               (((unsigned short)bufptr[1]) << 8) |
446                               (((unsigned short)bufptr[0]));
447                             r = (tmp >> 7) & 0xf8; r |= r >> 5;
448                             g = (tmp >> 2) & 0xf8; g |= g >> 5;
449                             b = (tmp << 3) & 0xf8; b |= b >> 5;
450                             a = 0xff;
451                             if ((hasa) && (tmp & 0x8000)) a = 0;
452                             bufptr += 2;
453                             for (i = 0; (i < count) && (dataptr < dataend); i++)
454                               {
455                                  *dataptr = ARGB_JOIN(a, r, g, b);
456                                  dataptr++;
457                               }
458                          }
459                        break;
460                     case 8:
461                        if (bufptr < (bufend - 1))
462                          {
463                             unsigned char g;
464 
465                             g = bufptr[0];
466                             bufptr += 1;
467                             for (i = 0; (i < count) && (dataptr < dataend); i++)
468                               {
469                                  *dataptr = ARGB_JOIN(0xff, g, g, g);
470                                  dataptr++;
471                               }
472                          }
473                        break;
474                     default:
475                        break;
476                     }
477                }
478              else // raw
479                {
480                   switch (bpp)
481                     {
482                     case 32:
483                        for (i = 0; (i < count) && (bufptr < (bufend - 4)) && (dataptr < dataend); i++)
484                          {
485                             if (hasa)
486 //                              *dataptr = ARGB_JOIN(255 - bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
487                               *dataptr = ARGB_JOIN(bufptr[3], bufptr[2], bufptr[1], bufptr[0]);
488                             else
489                               *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
490                             dataptr++;
491                             bufptr += 4;
492                          }
493                        break;
494                     case 24:
495                        for (i = 0; (i < count) && (bufptr < (bufend - 3)) && (dataptr < dataend); i++)
496                          {
497                             *dataptr = ARGB_JOIN(0xff, bufptr[2], bufptr[1], bufptr[0]);
498                             dataptr++;
499                             bufptr += 3;
500                          }
501                        break;
502                     case 16:
503                        for (i = 0; (i < count) && (bufptr < (bufend - 2)) && (dataptr < dataend); i++)
504                          {
505                             unsigned char r, g, b, a;
506                             unsigned short tmp;
507 
508                             tmp =
509                               (((unsigned short)bufptr[1]) << 8) |
510                               (((unsigned short)bufptr[0]));
511                             r = (tmp >> 7) & 0xf8; r |= r >> 5;
512                             g = (tmp >> 2) & 0xf8; g |= g >> 5;
513                             b = (tmp << 3) & 0xf8; b |= b >> 5;
514                             a = 0xff;
515                             if ((hasa) && (tmp & 0x8000)) a = 0;
516                             *dataptr = ARGB_JOIN(a, r, g, b);
517                             dataptr++;
518                             bufptr += 2;
519                          }
520                        break;
521                     case 8:
522                        for (i = 0; (i < count) && (bufptr < (bufend - 1)) && (dataptr < dataend); i++)
523                          {
524                             *dataptr = ARGB_JOIN(0xff, bufptr[0], bufptr[0], bufptr[0]);
525                             dataptr++;
526                             bufptr += 1;
527                          }
528                        break;
529                     default:
530                        break;
531                     }
532                }
533           }
534         if (vinverted)
535           {
536              unsigned int *adv, *adv2, tmp;
537 
538              adv = surface;
539              adv2 = surface + (w * (h - 1));
540              for (y = 0; y < (h / 2); y++)
541                {
542                   for (x = 0; x < w; x++)
543                     {
544                        tmp = adv[x];
545                        adv[x] = adv2[x];
546                        adv2[x] = tmp;
547                     }
548                   adv2 -= w;
549                   adv += w;
550                }
551           }
552      }
553 
554    prop->premul = EINA_TRUE;
555 
556    *error = EVAS_LOAD_ERROR_NONE;
557    res = EINA_TRUE;
558 
559  close_file:
560    if (seg != NULL) eina_file_map_free(f, seg);
561    return res;
562 }
563 
564 static Evas_Image_Load_Func evas_image_load_tga_func =
565 {
566   EVAS_IMAGE_LOAD_VERSION,
567   evas_image_load_file_open_tga,
568   evas_image_load_file_close_tga,
569   (void*) evas_image_load_file_head_tga,
570   NULL,
571   (void*) evas_image_load_file_data_tga,
572   NULL,
573   EINA_TRUE,
574   EINA_FALSE
575 };
576 
577 static int
module_open(Evas_Module * em)578 module_open(Evas_Module *em)
579 {
580    if (!em) return 0;
581    em->functions = (void *)(&evas_image_load_tga_func);
582    return 1;
583 }
584 
585 static void
module_close(Evas_Module * em EINA_UNUSED)586 module_close(Evas_Module *em EINA_UNUSED)
587 {
588 }
589 
590 static Evas_Module_Api evas_modapi =
591 {
592    EVAS_MODULE_API_VERSION,
593    "tga",
594    "none",
595    {
596      module_open,
597      module_close
598    }
599 };
600 
601 EVAS_MODULE_DEFINE(EVAS_MODULE_TYPE_IMAGE_LOADER, image_loader, tga);
602 
603 #ifndef EVAS_STATIC_BUILD_TGA
604 EVAS_EINA_MODULE_DEFINE(image_loader, tga);
605 #endif
606