1 /* -*- mode: C; c-file-style: "linux" -*- */
2 /*
3 * GdkPixbuf library - TGA image loader
4 * Copyright (C) 1999 Nicola Girardi <nikke@swlibero.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 /*
22 * Some NOTES about the TGA loader (2001/06/07, nikke@swlibero.org)
23 *
24 * - The TGAFooter isn't present in all TGA files. In fact, there's an older
25 * format specification, still in use, which doesn't cover the TGAFooter.
26 * Actually, most TGA files I have are of the older type. Anyway I put the
27 * struct declaration here for completeness.
28 *
29 * - Error handling was designed to be very paranoid.
30 */
31
32 #include "config.h"
33 #include <stdio.h>
34 #include <string.h>
35 #include <glib-object.h>
36 #include <glib/gi18n-lib.h>
37
38 #include "gdk-pixbuf-core.h"
39 #include "gdk-pixbuf-io.h"
40 #include "gdk-pixbuf-buffer-queue-private.h"
41
42 #undef DEBUG_TGA
43
44 #define TGA_INTERLEAVE_MASK 0xc0
45 #define TGA_INTERLEAVE_NONE 0x00
46 #define TGA_INTERLEAVE_2WAY 0x40
47 #define TGA_INTERLEAVE_4WAY 0x80
48
49 #define TGA_ORIGIN_MASK 0x30
50 #define TGA_ORIGIN_RIGHT 0x10
51 #define TGA_ORIGIN_UPPER 0x20
52
53 enum {
54 TGA_TYPE_NODATA = 0,
55 TGA_TYPE_PSEUDOCOLOR = 1,
56 TGA_TYPE_TRUECOLOR = 2,
57 TGA_TYPE_GRAYSCALE = 3,
58 TGA_TYPE_RLE_PSEUDOCOLOR = 9,
59 TGA_TYPE_RLE_TRUECOLOR = 10,
60 TGA_TYPE_RLE_GRAYSCALE = 11
61 };
62
63 #define LE16(p) ((p)[0] + ((p)[1] << 8))
64
65 typedef struct _TGAHeader TGAHeader;
66 typedef struct _TGAFooter TGAFooter;
67
68 typedef struct _TGAColor TGAColor;
69 typedef struct _TGAColormap TGAColormap;
70
71 typedef struct _TGAContext TGAContext;
72
73 struct _TGAHeader {
74 guint8 infolen;
75 guint8 has_cmap;
76 guint8 type;
77
78 guint8 cmap_start[2];
79 guint8 cmap_n_colors[2];
80 guint8 cmap_bpp;
81
82 guint8 x_origin[2];
83 guint8 y_origin[2];
84
85 guint8 width[2];
86 guint8 height[2];
87 guint8 bpp;
88
89 guint8 flags;
90 };
91
92 struct _TGAFooter {
93 guint32 extension_area_offset;
94 guint32 developer_directory_offset;
95
96 /* Standard TGA signature, "TRUEVISION-XFILE.\0". */
97 union {
98 gchar sig_full[18];
99 struct {
100 gchar sig_chunk[16];
101 gchar dot, null;
102 } sig_struct;
103 } sig;
104 };
105
106 struct _TGAColor {
107 guchar r, g, b, a;
108 };
109
110 struct _TGAColormap {
111 guint n_colors;
112 TGAColor colors[1];
113 };
114
115 typedef gboolean (* TGAProcessFunc) (TGAContext *ctx, GError **error);
116
117 struct _TGAContext {
118 TGAHeader *hdr;
119
120 TGAColormap *cmap;
121 guint cmap_size;
122
123 GdkPixbuf *pbuf;
124 int pbuf_x;
125 int pbuf_y;
126 int pbuf_y_notified;
127
128 GdkPixbufBufferQueue *input;
129
130 TGAProcessFunc process;
131
132 GdkPixbufModuleSizeFunc sfunc;
133 GdkPixbufModulePreparedFunc pfunc;
134 GdkPixbufModuleUpdatedFunc ufunc;
135 gpointer udata;
136 };
137
138 static TGAColormap *
colormap_new(guint n_colors)139 colormap_new (guint n_colors)
140 {
141 TGAColormap *cmap;
142
143 g_assert (n_colors <= G_MAXUINT16);
144
145 cmap = g_try_malloc0 (sizeof (TGAColormap) + (MAX (n_colors, 1) - 1) * sizeof (TGAColor));
146 if (cmap == NULL)
147 return NULL;
148
149 cmap->n_colors = n_colors;
150
151 return cmap;
152 }
153
154 static const TGAColor *
colormap_get_color(TGAColormap * cmap,guint id)155 colormap_get_color (TGAColormap *cmap,
156 guint id)
157 {
158 static const TGAColor transparent_black = { 0, 0, 0, 0 };
159
160 if (id >= cmap->n_colors)
161 return &transparent_black;
162
163 return &cmap->colors[id];
164 }
165
166 static void
colormap_set_color(TGAColormap * cmap,guint id,const TGAColor * color)167 colormap_set_color (TGAColormap *cmap,
168 guint id,
169 const TGAColor *color)
170 {
171 if (id >= cmap->n_colors)
172 return;
173
174 cmap->colors[id] = *color;
175 }
176
177 static void
colormap_free(TGAColormap * cmap)178 colormap_free (TGAColormap *cmap)
179 {
180 g_free (cmap);
181 }
182
183 static gboolean
tga_skip_rest_of_image(TGAContext * ctx,GError ** err)184 tga_skip_rest_of_image (TGAContext *ctx,
185 GError **err)
186 {
187 gdk_pixbuf_buffer_queue_flush (ctx->input, gdk_pixbuf_buffer_queue_get_size (ctx->input));
188
189 return TRUE;
190 }
191
192 static inline void
tga_write_pixel(TGAContext * ctx,const TGAColor * color)193 tga_write_pixel (TGAContext *ctx,
194 const TGAColor *color)
195 {
196 gint width = gdk_pixbuf_get_width (ctx->pbuf);
197 gint height = gdk_pixbuf_get_height (ctx->pbuf);
198 gint rowstride = gdk_pixbuf_get_rowstride (ctx->pbuf);
199 gint n_channels = gdk_pixbuf_get_n_channels (ctx->pbuf);
200
201 guint x = (ctx->hdr->flags & TGA_ORIGIN_RIGHT) ? width - ctx->pbuf_x - 1 : ctx->pbuf_x;
202 guint y = (ctx->hdr->flags & TGA_ORIGIN_UPPER) ? ctx->pbuf_y : height - ctx->pbuf_y - 1;
203
204 memcpy (gdk_pixbuf_get_pixels (ctx->pbuf) + y * rowstride + x * n_channels, color, n_channels);
205
206 ctx->pbuf_x++;
207 if (ctx->pbuf_x >= width)
208 {
209 ctx->pbuf_x = 0;
210 ctx->pbuf_y++;
211 }
212 }
213
214 static gsize
tga_pixels_remaining(TGAContext * ctx)215 tga_pixels_remaining (TGAContext *ctx)
216 {
217 gint width = gdk_pixbuf_get_width (ctx->pbuf);
218 gint height = gdk_pixbuf_get_height (ctx->pbuf);
219
220 return width * (height - ctx->pbuf_y) - ctx->pbuf_x;
221 }
222
223 static gboolean
tga_all_pixels_written(TGAContext * ctx)224 tga_all_pixels_written (TGAContext *ctx)
225 {
226 gint height = gdk_pixbuf_get_height (ctx->pbuf);
227
228 return ctx->pbuf_y >= height;
229 }
230
231 static void
tga_emit_update(TGAContext * ctx)232 tga_emit_update (TGAContext *ctx)
233 {
234 gint width = gdk_pixbuf_get_width (ctx->pbuf);
235 gint height = gdk_pixbuf_get_height (ctx->pbuf);
236
237 if (!ctx->ufunc)
238 return;
239
240 /* We only notify row-by-row for now.
241 * I was too lazy to handle line-breaks.
242 */
243 if (ctx->pbuf_y_notified == ctx->pbuf_y)
244 return;
245
246 if (ctx->hdr->flags & TGA_ORIGIN_UPPER)
247 (*ctx->ufunc) (ctx->pbuf,
248 0, ctx->pbuf_y_notified,
249 width, ctx->pbuf_y - ctx->pbuf_y_notified,
250 ctx->udata);
251 else
252 (*ctx->ufunc) (ctx->pbuf,
253 0, height - ctx->pbuf_y,
254 width, ctx->pbuf_y - ctx->pbuf_y_notified,
255 ctx->udata);
256
257 ctx->pbuf_y_notified = ctx->pbuf_y;
258 }
259
260 static gboolean
tga_format_supported(guint type,guint bits_per_pixel)261 tga_format_supported (guint type,
262 guint bits_per_pixel)
263 {
264 switch (type)
265 {
266 case TGA_TYPE_PSEUDOCOLOR:
267 case TGA_TYPE_RLE_PSEUDOCOLOR:
268 return bits_per_pixel == 8;
269
270 case TGA_TYPE_TRUECOLOR:
271 case TGA_TYPE_RLE_TRUECOLOR:
272 return bits_per_pixel == 16
273 || bits_per_pixel == 24
274 || bits_per_pixel == 32;
275
276 case TGA_TYPE_GRAYSCALE:
277 case TGA_TYPE_RLE_GRAYSCALE:
278 return bits_per_pixel == 8
279 || bits_per_pixel == 16;
280
281 default:
282 return FALSE;
283 }
284 }
285
286 static inline void
tga_read_pixel(TGAContext * ctx,const guchar * data,TGAColor * color)287 tga_read_pixel (TGAContext *ctx,
288 const guchar *data,
289 TGAColor *color)
290 {
291 switch (ctx->hdr->type)
292 {
293 case TGA_TYPE_PSEUDOCOLOR:
294 case TGA_TYPE_RLE_PSEUDOCOLOR:
295 *color = *colormap_get_color (ctx->cmap, data[0]);
296 break;
297
298 case TGA_TYPE_TRUECOLOR:
299 case TGA_TYPE_RLE_TRUECOLOR:
300 if (ctx->hdr->bpp == 16)
301 {
302 guint16 col = data[0] + (data[1] << 8);
303 color->r = (col >> 7) & 0xf8;
304 color->r |= color->r >> 5;
305 color->g = (col >> 2) & 0xf8;
306 color->g |= color->g >> 5;
307 color->b = col << 3;
308 color->b |= color->b >> 5;
309 color->a = 255;
310 }
311 else
312 {
313 color->b = data[0];
314 color->g = data[1];
315 color->r = data[2];
316 if (ctx->hdr->bpp == 32)
317 color->a = data[3];
318 else
319 color->a = 255;
320 }
321 break;
322
323 case TGA_TYPE_GRAYSCALE:
324 case TGA_TYPE_RLE_GRAYSCALE:
325 color->r = color->g = color->b = data[0];
326 if (ctx->hdr->bpp == 16)
327 color->a = data[1];
328 else
329 color->a = 255;
330 break;
331
332 default:
333 g_assert_not_reached ();
334 }
335 }
336
fill_in_context(TGAContext * ctx,GError ** err)337 static gboolean fill_in_context(TGAContext *ctx, GError **err)
338 {
339 gboolean alpha;
340 guint w, h;
341
342 g_return_val_if_fail(ctx != NULL, FALSE);
343
344 ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
345 LE16(ctx->hdr->cmap_n_colors);
346 ctx->cmap = colormap_new (LE16(ctx->hdr->cmap_n_colors));
347 if (!ctx->cmap) {
348 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
349 _("Cannot allocate colormap"));
350 return FALSE;
351 }
352
353 alpha = ((ctx->hdr->bpp == 16) ||
354 (ctx->hdr->bpp == 32) ||
355 (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
356
357 w = LE16(ctx->hdr->width);
358 h = LE16(ctx->hdr->height);
359
360 if (ctx->sfunc) {
361 gint wi = w;
362 gint hi = h;
363
364 (*ctx->sfunc) (&wi, &hi, ctx->udata);
365
366 if (wi == 0 || hi == 0)
367 return FALSE;
368 }
369
370 ctx->pbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, alpha, 8, w, h);
371
372 if (!ctx->pbuf) {
373 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
374 _("Cannot allocate new pixbuf"));
375 return FALSE;
376 }
377
378 return TRUE;
379 }
380
381 static gboolean
tga_load_image(TGAContext * ctx,GError ** err)382 tga_load_image (TGAContext *ctx,
383 GError **err)
384 {
385 TGAColor color;
386 GBytes *bytes;
387 gsize i, size, bytes_per_pixel;
388 const guchar *data;
389
390 bytes_per_pixel = (ctx->hdr->bpp + 7) / 8;
391 size = gdk_pixbuf_buffer_queue_get_size (ctx->input) / bytes_per_pixel;
392 size = MIN (size, tga_pixels_remaining (ctx));
393
394 bytes = gdk_pixbuf_buffer_queue_pull (ctx->input, size * bytes_per_pixel);
395 g_assert (bytes != NULL);
396
397 data = g_bytes_get_data (bytes, NULL);
398
399 for (i = 0; i < size; i++)
400 {
401 tga_read_pixel (ctx, data, &color);
402 tga_write_pixel (ctx, &color);
403 data += bytes_per_pixel;
404 }
405
406 g_bytes_unref (bytes);
407
408 tga_emit_update (ctx);
409
410 if (tga_all_pixels_written (ctx))
411 ctx->process = tga_skip_rest_of_image;
412 return TRUE;
413 }
414
415 static gboolean
tga_load_rle_image(TGAContext * ctx,GError ** err)416 tga_load_rle_image (TGAContext *ctx,
417 GError **err)
418 {
419 GBytes *bytes;
420 TGAColor color;
421 guint rle_num, raw_num;
422 const guchar *s;
423 guchar tag;
424 gsize n, size, bytes_per_pixel;
425
426 bytes_per_pixel = (ctx->hdr->bpp + 7) / 8;
427 bytes = gdk_pixbuf_buffer_queue_peek (ctx->input, gdk_pixbuf_buffer_queue_get_size (ctx->input));
428 s = g_bytes_get_data (bytes, &size);
429
430 for (n = 0; n < size; ) {
431 tag = *s;
432 s++, n++;
433 if (tag & 0x80) {
434 if (n + bytes_per_pixel > size) {
435 --n;
436 break;
437 } else {
438 rle_num = (tag & 0x7f) + 1;
439 tga_read_pixel (ctx, s, &color);
440 s += bytes_per_pixel;
441 n += bytes_per_pixel;
442 rle_num = MIN (rle_num, tga_pixels_remaining (ctx));
443 for (; rle_num; rle_num--)
444 {
445 tga_write_pixel (ctx, &color);
446 }
447 if (tga_all_pixels_written (ctx))
448 break;
449 }
450 } else {
451 raw_num = tag + 1;
452 if (n + (raw_num * bytes_per_pixel) > size) {
453 --n;
454 break;
455 } else {
456 raw_num = MIN (raw_num, tga_pixels_remaining (ctx));
457 for (; raw_num; raw_num--) {
458 tga_read_pixel (ctx, s, &color);
459 s += bytes_per_pixel;
460 n += bytes_per_pixel;
461 tga_write_pixel (ctx, &color);
462 }
463
464 if (tga_all_pixels_written (ctx))
465 break;
466 }
467 }
468 }
469
470 g_bytes_unref (bytes);
471 gdk_pixbuf_buffer_queue_flush (ctx->input, n);
472
473 tga_emit_update (ctx);
474
475 if (tga_all_pixels_written (ctx))
476 ctx->process = tga_skip_rest_of_image;
477 return TRUE;
478 }
479
480 static gboolean
tga_load_colormap(TGAContext * ctx,GError ** err)481 tga_load_colormap (TGAContext *ctx,
482 GError **err)
483 {
484 GBytes *bytes;
485 TGAColor color;
486 const guchar *p;
487 guint i, n_colors;
488
489 if (ctx->hdr->has_cmap)
490 {
491 bytes = gdk_pixbuf_buffer_queue_pull (ctx->input, ctx->cmap_size);
492 if (bytes == NULL)
493 return TRUE;
494
495 n_colors = LE16(ctx->hdr->cmap_n_colors);
496
497 p = g_bytes_get_data (bytes, NULL);
498 color.a = 255;
499
500 for (i = 0; i < n_colors; i++)
501 {
502 if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16))
503 {
504 guint16 col = p[0] + (p[1] << 8);
505 color.b = (col >> 7) & 0xf8;
506 color.g = (col >> 2) & 0xf8;
507 color.r = col << 3;
508 p += 2;
509 }
510 else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32))
511 {
512 color.b = *p++;
513 color.g = *p++;
514 color.r = *p++;
515 if (ctx->hdr->cmap_bpp == 32)
516 color.a = *p++;
517 }
518 else
519 {
520 g_set_error_literal (err, GDK_PIXBUF_ERROR,
521 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
522 _("Unexpected bitdepth for colormap entries"));
523 g_bytes_unref (bytes);
524 return FALSE;
525 }
526 colormap_set_color (ctx->cmap, i, &color);
527 }
528
529 g_bytes_unref (bytes);
530 }
531 else
532 {
533 if ((ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
534 || (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR))
535 {
536 g_set_error_literal (err, GDK_PIXBUF_ERROR,
537 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
538 _("Pseudocolor image does not contain a colormap"));
539 return FALSE;
540 }
541 }
542
543 if ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
544 || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
545 || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE))
546 ctx->process = tga_load_rle_image;
547 else
548 ctx->process = tga_load_image;
549
550 return TRUE;
551 }
552
553 static gboolean
tga_read_info(TGAContext * ctx,GError ** err)554 tga_read_info (TGAContext *ctx,
555 GError **err)
556 {
557 if (gdk_pixbuf_buffer_queue_get_size (ctx->input) < ctx->hdr->infolen)
558 return TRUE;
559
560 gdk_pixbuf_buffer_queue_flush (ctx->input, ctx->hdr->infolen);
561
562 ctx->process = tga_load_colormap;
563 return TRUE;
564 }
565
566 static gboolean
tga_load_header(TGAContext * ctx,GError ** err)567 tga_load_header (TGAContext *ctx,
568 GError **err)
569 {
570 GBytes *bytes;
571
572 bytes = gdk_pixbuf_buffer_queue_pull (ctx->input, sizeof (TGAHeader));
573 if (bytes == NULL)
574 return TRUE;
575
576 ctx->hdr = g_try_malloc (sizeof (TGAHeader));
577 if (!ctx->hdr)
578 {
579 g_set_error_literal (err, GDK_PIXBUF_ERROR,
580 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
581 _("Cannot allocate TGA header memory"));
582 return FALSE;
583 }
584 memmove(ctx->hdr, g_bytes_get_data (bytes, NULL), sizeof(TGAHeader));
585 g_bytes_unref (bytes);
586 #ifdef DEBUG_TGA
587 g_print ("infolen %d "
588 "has_cmap %d "
589 "type %d "
590 "cmap_start %d "
591 "cmap_n_colors %d "
592 "cmap_bpp %d "
593 "x %d y %d width %d height %d bpp %d "
594 "flags %#x",
595 ctx->hdr->infolen,
596 ctx->hdr->has_cmap,
597 ctx->hdr->type,
598 LE16(ctx->hdr->cmap_start),
599 LE16(ctx->hdr->cmap_n_colors),
600 ctx->hdr->cmap_bpp,
601 LE16(ctx->hdr->x_origin),
602 LE16(ctx->hdr->y_origin),
603 LE16(ctx->hdr->width),
604 LE16(ctx->hdr->height),
605 ctx->hdr->bpp,
606 ctx->hdr->flags);
607 #endif
608 if (LE16(ctx->hdr->width) == 0 ||
609 LE16(ctx->hdr->height) == 0) {
610 g_set_error_literal(err, GDK_PIXBUF_ERROR,
611 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
612 _("TGA image has invalid dimensions"));
613 return FALSE;
614 }
615 if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
616 g_set_error_literal(err, GDK_PIXBUF_ERROR,
617 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
618 _("TGA image type not supported"));
619 return FALSE;
620 }
621 if (!tga_format_supported (ctx->hdr->type, ctx->hdr->bpp))
622 {
623 g_set_error_literal(err, GDK_PIXBUF_ERROR,
624 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
625 _("TGA image type not supported"));
626 return FALSE;
627 }
628
629 if (!fill_in_context(ctx, err))
630 return FALSE;
631
632 if (ctx->pfunc)
633 (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
634
635 ctx->process = tga_read_info;
636 return TRUE;
637 }
638
gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,GdkPixbufModulePreparedFunc f1,GdkPixbufModuleUpdatedFunc f2,gpointer udata,GError ** err)639 static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
640 GdkPixbufModulePreparedFunc f1,
641 GdkPixbufModuleUpdatedFunc f2,
642 gpointer udata, GError **err)
643 {
644 TGAContext *ctx;
645
646 ctx = g_try_malloc(sizeof(TGAContext));
647 if (!ctx) {
648 g_set_error_literal(err, GDK_PIXBUF_ERROR,
649 GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
650 _("Cannot allocate memory for TGA context struct"));
651 return NULL;
652 }
653
654 ctx->hdr = NULL;
655
656 ctx->cmap = NULL;
657 ctx->cmap_size = 0;
658
659 ctx->pbuf = NULL;
660 ctx->pbuf_x = 0;
661 ctx->pbuf_y = 0;
662 ctx->pbuf_y_notified = 0;
663
664 ctx->input = gdk_pixbuf_buffer_queue_new ();
665
666 ctx->process = tga_load_header;
667
668 ctx->sfunc = f0;
669 ctx->pfunc = f1;
670 ctx->ufunc = f2;
671 ctx->udata = udata;
672
673 return ctx;
674 }
675
gdk_pixbuf__tga_load_increment(gpointer data,const guchar * buffer,guint size,GError ** err)676 static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
677 const guchar *buffer,
678 guint size,
679 GError **err)
680 {
681 TGAContext *ctx = (TGAContext*) data;
682 TGAProcessFunc process;
683
684 g_return_val_if_fail(buffer != NULL, TRUE);
685 gdk_pixbuf_buffer_queue_push (ctx->input, g_bytes_new (buffer, size));
686
687 do
688 {
689 process = ctx->process;
690
691 if (!process (ctx, err))
692 return FALSE;
693 }
694 while (process != ctx->process);
695
696 return TRUE;
697 }
698
gdk_pixbuf__tga_stop_load(gpointer data,GError ** err)699 static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
700 {
701 TGAContext *ctx = (TGAContext *) data;
702 gboolean result = TRUE;
703
704 g_return_val_if_fail (ctx != NULL, FALSE);
705
706 if (ctx->pbuf == NULL || tga_pixels_remaining (ctx))
707 {
708 g_set_error_literal (err,
709 GDK_PIXBUF_ERROR,
710 GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
711 _("TGA image was truncated or incomplete."));
712
713 result = FALSE;
714 }
715
716 g_free (ctx->hdr);
717 if (ctx->cmap)
718 colormap_free (ctx->cmap);
719 if (ctx->pbuf)
720 g_object_unref (ctx->pbuf);
721 gdk_pixbuf_buffer_queue_unref (ctx->input);
722 g_free (ctx);
723
724 return result;
725 }
726
727 #ifndef INCLUDE_tga
728 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
729 #else
730 #define MODULE_ENTRY(function) void _gdk_pixbuf__tga_ ## function
731 #endif
732
MODULE_ENTRY(fill_vtable)733 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
734 {
735 module->begin_load = gdk_pixbuf__tga_begin_load;
736 module->stop_load = gdk_pixbuf__tga_stop_load;
737 module->load_increment = gdk_pixbuf__tga_load_increment;
738 }
739
MODULE_ENTRY(fill_info)740 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
741 {
742 static const GdkPixbufModulePattern signature[] = {
743 { " \x1\x1", "x ", 100 },
744 { " \x1\x9", "x ", 100 },
745 { " \x2", "xz ", 99 }, /* only 99 since .CUR also matches this */
746 { " \x3", "xz ", 100 },
747 { " \xa", "xz ", 100 },
748 { " \xb", "xz ", 100 },
749 { NULL, NULL, 0 }
750 };
751 static const gchar *mime_types[] = {
752 "image/x-tga",
753 NULL
754 };
755 static const gchar *extensions[] = {
756 "tga",
757 "targa",
758 NULL
759 };
760
761 info->name = "tga";
762 info->signature = (GdkPixbufModulePattern *) signature;
763 info->description = NC_("image format", "Targa");
764 info->mime_types = (gchar **) mime_types;
765 info->extensions = (gchar **) extensions;
766 info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
767 info->license = "LGPL";
768 }
769