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