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