]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-tga.c
Make it possible to call gdk_pixbuf_loader_set_size (loader, 0, 0) by
[~andy/gtk] / gdk-pixbuf / io-tga.c
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, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  */
22
23 /*
24  * Some NOTES about the TGA loader (2001/06/07, nikke@swlibero.org)
25  *
26  * - The module doesn't currently provide support for TGA images where the
27  *   order of the pixels isn't left-to-right and top-to-bottom.  I plan to
28  *   add support for those files as soon as I get one of them.  I haven't
29  *   run into one yet.  (And I don't seem to be able to create it with GIMP.)
30  *
31  * - The TGAFooter isn't present in all TGA files.  In fact, there's an older
32  *   format specification, still in use, which doesn't cover the TGAFooter.
33  *   Actually, most TGA files I have are of the older type.  Anyway I put the 
34  *   struct declaration here for completeness.
35  *
36  * - Error handling was designed to be very paranoid.
37  */
38
39 #include <stdio.h>
40 #include <string.h>
41
42 #include "gdk-pixbuf-private.h"
43 #include "gdk-pixbuf-io.h"
44
45 #undef DEBUG_TGA
46
47 #define TGA_INTERLEAVE_MASK     0xc0
48 #define TGA_INTERLEAVE_NONE     0x00
49 #define TGA_INTERLEAVE_2WAY     0x40
50 #define TGA_INTERLEAVE_4WAY     0x80
51
52 #define TGA_ORIGIN_MASK         0x30
53 #define TGA_ORIGIN_RIGHT        0x10
54 #define TGA_ORIGIN_UPPER        0x20
55
56 enum {
57         TGA_TYPE_NODATA = 0,
58         TGA_TYPE_PSEUDOCOLOR = 1,
59         TGA_TYPE_TRUECOLOR = 2,
60         TGA_TYPE_GRAYSCALE = 3,
61         TGA_TYPE_RLE_PSEUDOCOLOR = 9,
62         TGA_TYPE_RLE_TRUECOLOR = 10,
63         TGA_TYPE_RLE_GRAYSCALE = 11
64 };
65
66 #define LE16(p) ((p)[0] + ((p)[1] << 8))
67
68 typedef struct _IOBuffer IOBuffer;
69
70 typedef struct _TGAHeader TGAHeader;
71 typedef struct _TGAFooter TGAFooter;
72
73 typedef struct _TGAColormap TGAColormap;
74 typedef struct _TGAColor TGAColor;
75
76 typedef struct _TGAContext TGAContext;
77
78 struct _TGAHeader {
79         guint8 infolen;
80         guint8 has_cmap;
81         guint8 type;
82         
83         guint8 cmap_start[2];
84         guint8 cmap_n_colors[2];
85         guint8 cmap_bpp;
86         
87         guint8 x_origin[2];
88         guint8 y_origin[2];
89         
90         guint8 width[2];
91         guint8 height[2];
92         guint8 bpp;
93         
94         guint8 flags;
95 };
96
97 struct _TGAFooter {
98         guint32 extension_area_offset;
99         guint32 developer_directory_offset;
100
101         /* Standard TGA signature, "TRUEVISION-XFILE.\0". */
102         union {
103                 gchar sig_full[18];
104                 struct {
105                         gchar sig_chunk[16];
106                         gchar dot, null;
107                 } sig_struct;
108         } sig;
109 };
110
111 struct _TGAColormap {
112         gint size;
113         TGAColor *cols;
114 };
115
116 struct _TGAColor {
117         guchar r, g, b, a;
118 };
119
120 struct _TGAContext {
121         TGAHeader *hdr;
122         guint rowstride;
123         guint completed_lines;
124         gboolean run_length_encoded;
125
126         TGAColormap *cmap;
127         guint cmap_size;
128
129         GdkPixbuf *pbuf;
130         guint pbuf_bytes;
131         guint pbuf_bytes_done;
132         guchar *pptr;
133
134         IOBuffer *in;
135
136         gboolean skipped_info;
137         gboolean prepared;
138         gboolean done;
139
140         GdkPixbufModuleSizeFunc sfunc;
141         GdkPixbufModulePreparedFunc pfunc;
142         GdkPixbufModuleUpdatedFunc ufunc;
143         gpointer udata;
144 };
145
146 struct _IOBuffer {
147         guchar *data;
148         guint size;
149 };
150
151 static IOBuffer *io_buffer_new(GError **err)
152 {
153         IOBuffer *buffer;
154         buffer = g_try_malloc(sizeof(IOBuffer));
155         if (!buffer) {
156                 g_set_error(err, GDK_PIXBUF_ERROR,
157                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
158                             _("Can't allocate memory for IOBuffer struct"));
159                 return NULL;
160         }
161         buffer->data = NULL;
162         buffer->size = 0;
163         return buffer;
164 }
165
166 static IOBuffer *io_buffer_append(IOBuffer *buffer, 
167                                   const guchar *data, guint len, 
168                                   GError **err)
169 {
170         if (!buffer)
171                 return NULL;
172         if (!buffer->data) {
173                 buffer->data = g_try_malloc(len);
174                 if (!buffer->data) {
175                         g_set_error(err, GDK_PIXBUF_ERROR,
176                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
177                                     _("Can't allocate memory for IOBuffer data"));
178                         g_free(buffer);
179                         return NULL;
180                 }
181                 g_memmove(buffer->data, data, len);
182                 buffer->size = len;
183         } else {
184                 guchar *tmp = g_try_realloc (buffer->data, buffer->size + len);
185                 if (!tmp) {
186                         g_set_error(err, GDK_PIXBUF_ERROR,
187                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
188                                     _("Can't realloc IOBuffer data"));
189                         g_free(buffer);
190                         return NULL;
191                 }
192                 buffer->data = tmp;
193                 g_memmove(&buffer->data[buffer->size], data, len);
194                 buffer->size += len;
195         }
196         return buffer;
197 }
198
199 static IOBuffer *io_buffer_free_segment(IOBuffer *buffer, 
200                                         guint count,
201                                         GError **err)
202 {
203         g_return_val_if_fail(buffer != NULL, NULL);
204         g_return_val_if_fail(buffer->data != NULL, NULL);
205         if (count == buffer->size) {
206                 g_free(buffer->data);
207                 buffer->data = NULL;
208                 buffer->size = 0;
209         } else {
210                 guchar *new_buf;
211                 guint new_size;
212
213                 new_size = buffer->size - count;
214                 new_buf = g_try_malloc(new_size);
215                 if (!new_buf) {
216                         g_set_error(err, GDK_PIXBUF_ERROR,
217                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
218                                     _("Can't allocate temporary IOBuffer data"));
219                         g_free(buffer->data);
220                         g_free(buffer);
221                         return NULL;
222                 }
223
224                 g_memmove(new_buf, &buffer->data[count], new_size);
225                 g_free(buffer->data);
226                 buffer->data = new_buf;
227                 buffer->size = new_size;
228         }
229         return buffer;
230 }
231
232 static void io_buffer_free(IOBuffer *buffer)
233 {
234         g_return_if_fail(buffer != NULL);
235         if (buffer->data)
236                 g_free(buffer->data);
237         g_free(buffer);
238 }
239
240 static void free_buffer(guchar *pixels, gpointer data)
241 {
242         g_free(pixels);
243 }
244
245 static GdkPixbuf *get_contiguous_pixbuf (guint width, 
246                                          guint height, 
247                                          gboolean has_alpha)
248 {
249         guchar *pixels;
250         guint channels, rowstride, bytes;
251         
252         if (has_alpha) 
253                 channels = 4;
254         else 
255                 channels = 3;
256         
257         rowstride = width * channels;
258         
259         if (rowstride / channels != width)
260                 return NULL;                
261
262         bytes = height * rowstride;
263
264         if (bytes / rowstride != height)
265                 return NULL;                
266
267         pixels = g_try_malloc (bytes);
268
269         if (!pixels)
270                 return NULL;
271         
272         return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, has_alpha, 8,
273                                          width, height, rowstride, free_buffer, NULL);
274 }
275
276 static void pixbuf_flip_row (GdkPixbuf *pixbuf, guchar *ph)
277 {
278         guchar *p, *s;
279         guchar tmp;
280         gint count;
281
282         p = ph;
283         s = p + pixbuf->n_channels * (pixbuf->width - 1);
284         while (p < s) {
285                 for (count = pixbuf->n_channels; count > 0; count--, p++, s++) {
286                         tmp = *p;
287                         *p = *s;
288                         *s = tmp;
289                 }
290                 s -= 2 * pixbuf->n_channels;
291         }               
292 }
293
294 static void pixbuf_flip_vertically (GdkPixbuf *pixbuf)
295 {
296         guchar *ph, *sh, *p, *s;
297         guchar tmp;
298         gint count;
299
300         ph = pixbuf->pixels;
301         sh = pixbuf->pixels + pixbuf->height*pixbuf->rowstride;
302         while (ph < sh - pixbuf->rowstride) {
303                 p = ph;
304                 s = sh - pixbuf->rowstride;
305                 for (count = pixbuf->n_channels * pixbuf->width; count > 0; count--, p++, s++) {
306                         tmp = *p;
307                         *p = *s;
308                         *s = tmp;
309                 }
310                 sh -= pixbuf->rowstride;
311                 ph += pixbuf->rowstride;
312         }
313 }
314
315 static gboolean fill_in_context(TGAContext *ctx, GError **err)
316 {
317         gboolean alpha;
318         guint w, h;
319
320         g_return_val_if_fail(ctx != NULL, FALSE);
321
322         ctx->run_length_encoded =
323                 ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
324                  || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
325                  || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE));
326
327         if (ctx->hdr->has_cmap)
328                 ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
329                         LE16(ctx->hdr->cmap_n_colors);
330
331         alpha = ((ctx->hdr->bpp == 16) || 
332                  (ctx->hdr->bpp == 32) ||
333                  (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
334
335         w = LE16(ctx->hdr->width);
336         h = LE16(ctx->hdr->height);
337
338         if (ctx->sfunc) {
339                 gint wi = w;
340                 gint hi = h;
341                 
342                 (*ctx->sfunc) (&wi, &hi, ctx->udata);
343                 
344                 if (wi == 0 || hi == 0) 
345                         return FALSE;
346         }
347
348         ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
349
350         if (!ctx->pbuf) {
351                 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
352                             _("Can't allocate new pixbuf"));
353                 return FALSE;
354         }
355
356         ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
357         if (ctx->hdr->flags & TGA_ORIGIN_UPPER || ctx->run_length_encoded)
358                 ctx->pptr = ctx->pbuf->pixels;
359         else
360                 ctx->pptr = ctx->pbuf->pixels + (ctx->pbuf->height - 1)*ctx->pbuf->rowstride;
361
362         if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
363           ctx->rowstride = ctx->pbuf->width;
364         else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
365           ctx->rowstride = (alpha ? ctx->pbuf->width * 2 : ctx->pbuf->width);
366         else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
367                 ctx->rowstride = ctx->pbuf->rowstride;
368
369         ctx->completed_lines = 0;
370         return TRUE;
371 }
372
373 static void parse_data_for_row_pseudocolor(TGAContext *ctx)
374 {
375         guchar *s = ctx->in->data;
376         guint upper_bound = ctx->pbuf->width;
377         guchar *p = ctx->pptr;
378
379         for (; upper_bound; upper_bound--, s++) {
380                 *p++ = ctx->cmap->cols[*s].r;
381                 *p++ = ctx->cmap->cols[*s].g;
382                 *p++ = ctx->cmap->cols[*s].b;
383                 if (ctx->hdr->cmap_bpp == 32)
384                         *p++ = ctx->cmap->cols[*s].a;
385         }
386 }
387
388 static void swap_channels(TGAContext *ctx)
389 {
390         guchar swap;
391         guint count;
392         guchar *p = ctx->pptr;
393         for (count = ctx->pbuf->width; count; count--) {
394           swap = p[0];
395           p[0] = p[2];
396           p[2] = swap;
397           p += ctx->pbuf->n_channels;
398         }
399 }
400
401 static void parse_data_for_row_truecolor(TGAContext *ctx)
402 {
403         g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
404         swap_channels(ctx);
405 }
406
407 static void parse_data_for_row_grayscale(TGAContext *ctx)
408 {
409         guchar *s = ctx->in->data;
410         guint upper_bound = ctx->pbuf->width;
411
412         guchar *p = ctx->pptr;
413         for (; upper_bound; upper_bound--) {
414                 p[0] = p[1] = p[2] = *s++;
415                 if (ctx->pbuf->n_channels == 4)
416                   p[3] = *s++;
417                 p += ctx->pbuf->n_channels;
418         }
419 }
420
421 static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
422 {
423         guint row;
424
425         if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
426                 parse_data_for_row_pseudocolor(ctx);
427         else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
428                 parse_data_for_row_truecolor(ctx);
429         else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
430                 parse_data_for_row_grayscale(ctx);
431
432         if (ctx->hdr->flags & TGA_ORIGIN_RIGHT)
433                 pixbuf_flip_row (ctx->pbuf, ctx->pptr);
434         if (ctx->hdr->flags & TGA_ORIGIN_UPPER)
435                 ctx->pptr += ctx->pbuf->rowstride;
436         else
437                 ctx->pptr -= ctx->pbuf->rowstride;
438         ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
439         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
440                 ctx->done = TRUE;
441         
442         ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err);
443         if (!ctx->in)
444                 return FALSE;
445         row = (ctx->pptr - ctx->pbuf->pixels) / ctx->pbuf->rowstride - 1;
446         if (ctx->ufunc)
447                 (*ctx->ufunc) (ctx->pbuf, 0, row, ctx->pbuf->width, 1, ctx->udata);
448         return TRUE;
449 }
450
451 static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
452 {
453         for (; *rle_count; (*rle_count)--) {
454                 g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
455                 ctx->pptr += ctx->pbuf->n_channels;
456                 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
457                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
458                         return;
459         }
460 }
461
462 static guint parse_rle_data_pseudocolor(TGAContext *ctx)
463 {
464         guint rle_num, raw_num;
465         guchar *s, tag;
466         guint n;
467
468         g_return_val_if_fail(ctx->in->size > 0, 0);
469         s = ctx->in->data;
470
471         for (n = 0; n < ctx->in->size; ) {
472                 tag = *s;
473                 s++, n++;
474                 if (tag & 0x80) {
475                         if (n == ctx->in->size) {
476                                 return --n;
477                         } else {
478                                 rle_num = (tag & 0x7f) + 1;
479                                 write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
480                                 s++, n++;
481                                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
482                                         ctx->done = TRUE;
483                                         return n;
484                                 }
485                         }
486                 } else {
487                         raw_num = tag + 1;
488                         if (n + raw_num >= ctx->in->size) {
489                                 return --n;
490                         } else {
491                                 for (; raw_num; raw_num--) {
492                                         *ctx->pptr++ =
493                                                 ctx->cmap->cols[*s].r;
494                                         *ctx->pptr++ =
495                                                 ctx->cmap->cols[*s].g;
496                                         *ctx->pptr++ =
497                                                 ctx->cmap->cols[*s].b;
498                                         if (ctx->pbuf->n_channels == 4)
499                                                 *ctx->pptr++ = ctx->cmap->cols[*s].a;
500                                         s++, n++;
501                                         ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
502                                         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
503                                                 ctx->done = TRUE;
504                                                 return n;
505                                         }
506                                 }
507                         }
508                 }
509         }
510
511         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
512                 ctx->done = TRUE;
513         return n;
514 }
515
516 static guint parse_rle_data_truecolor(TGAContext *ctx)
517 {
518         TGAColor col;
519         guint rle_num, raw_num;
520         guchar *s, tag;
521         guint n = 0;
522
523         g_return_val_if_fail(ctx->in->size > 0, 0);
524         s = ctx->in->data;
525
526         for (n = 0; n < ctx->in->size; ) {
527                 tag = *s;
528                 s++, n++;
529                 if (tag & 0x80) {
530                         if (n + ctx->pbuf->n_channels >= ctx->in->size) {
531                                 return --n;
532                         } else {
533                                 rle_num = (tag & 0x7f) + 1;
534                                 col.b = *s++;
535                                 col.g = *s++;
536                                 col.r = *s++;
537                                 if (ctx->hdr->bpp == 32)
538                                         col.a = *s++;
539                                 n += ctx->pbuf->n_channels;
540                                 write_rle_data(ctx, &col, &rle_num);
541                                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
542                                         ctx->done = TRUE;
543                                         return n;
544                                 }
545                         }
546                 } else {
547                         raw_num = tag + 1;
548                         if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
549                                 return --n;
550                         } else {
551                                 for (; raw_num; raw_num--) {
552                                         ctx->pptr[2] = *s++;
553                                         ctx->pptr[1] = *s++;
554                                         ctx->pptr[0] = *s++;
555                                         if (ctx->hdr->bpp == 32)
556                                                 ctx->pptr[3] = *s++;
557                                         n += ctx->pbuf->n_channels;
558                                         ctx->pptr += ctx->pbuf->n_channels;
559                                         ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
560                                         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
561                                                 ctx->done = TRUE;
562                                                 return n;
563                                         }
564                                 }
565                                 
566                                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
567                                         ctx->done = TRUE;
568                                         return n;
569                                 }
570                         }
571                 }
572         }
573         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
574                 ctx->done = TRUE;
575         return n;
576 }
577
578 static guint parse_rle_data_grayscale(TGAContext *ctx)
579 {
580         TGAColor tone;
581         guint rle_num, raw_num;
582         guchar *s, tag;
583         guint n;
584
585         g_return_val_if_fail(ctx->in->size > 0, 0);
586         s = ctx->in->data;
587
588         for (n = 0; n < ctx->in->size; ) {
589                 tag = *s;
590                 s++, n++;
591                 if (tag & 0x80) {
592                         if (n + (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
593                                 return --n;
594                         } else {
595                                 rle_num = (tag & 0x7f) + 1;
596                                 tone.r = tone.g = tone.b = *s;
597                                 s++, n++;
598                                 if (ctx->pbuf->n_channels == 4) {
599                                         tone.a = *s++;
600                                         n++;
601                                 }
602                                 write_rle_data(ctx, &tone, &rle_num);
603                                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
604                                         ctx->done = TRUE;
605                                         return n;
606                                 }
607                         }
608                 } else {
609                         raw_num = tag + 1;
610                         if (n + raw_num * (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
611                                 return --n;
612                         } else {
613                                 for (; raw_num; raw_num--) {
614                                         ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
615                                         s++, n++;
616                                         if (ctx->pbuf->n_channels == 4) {
617                                                 ctx->pptr[3] = *s++;
618                                                 n++;
619                                         }
620                                         ctx->pptr += ctx->pbuf->n_channels;
621                                         ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
622                                         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
623                                                 ctx->done = TRUE;
624                                                 return n;
625                                         }
626                                 }
627                         }
628                 }
629         }
630         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
631                 ctx->done = TRUE;
632         return n;
633 }
634
635 static gboolean parse_rle_data(TGAContext *ctx, GError **err)
636 {
637         guint count = 0;
638         guint pbuf_count = 0;
639         guint bytes_done_before = ctx->pbuf_bytes_done;
640         if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR) {
641                 count = parse_rle_data_pseudocolor(ctx);
642                 pbuf_count = count * ctx->pbuf->n_channels;
643         } else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR) {
644                 count = parse_rle_data_truecolor(ctx);
645                 pbuf_count = count;
646         } else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE) {
647                 count = parse_rle_data_grayscale(ctx);
648                 pbuf_count = count * (ctx->pbuf->n_channels == 4 ? 2 : 3);
649         }
650
651         if (ctx->hdr->flags & TGA_ORIGIN_RIGHT) {
652                 guchar *row = ctx->pbuf->pixels + (bytes_done_before / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
653                 guchar *row_after = ctx->pbuf->pixels + (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
654                 for (; row < row_after; row += ctx->pbuf->rowstride)
655                         pixbuf_flip_row (ctx->pbuf, row);
656         }
657
658         ctx->in = io_buffer_free_segment(ctx->in, count, err);
659         if (!ctx->in)
660                 return FALSE;
661
662         if (ctx->done) {
663                 /* FIXME doing the vertical flipping afterwards is not
664                  * perfect, but doing it during the rle decoding in place
665                  * is considerably more work. 
666                  */
667                 if (!(ctx->hdr->flags & TGA_ORIGIN_UPPER))
668                         pixbuf_flip_vertically (ctx->pbuf);
669         }
670
671         if (ctx->ufunc)
672                 (*ctx->ufunc) (ctx->pbuf, 0, ctx->pbuf_bytes_done / ctx->pbuf->rowstride,
673                                ctx->pbuf->width, pbuf_count / ctx->pbuf->rowstride,
674                                ctx->udata);
675
676
677         return TRUE;
678 }
679
680 static gboolean try_colormap(TGAContext *ctx, GError **err)
681 {
682         static guchar *p;
683         static guint n;
684
685         g_return_val_if_fail(ctx != NULL, FALSE);
686         g_return_val_if_fail(ctx->cmap_size > 0, TRUE);
687
688         ctx->cmap = g_try_malloc(sizeof(TGAColormap));
689         if (!ctx->cmap) {
690                 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
691                             _("Can't allocate colormap structure"));
692                 return FALSE;
693         }
694         ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
695         ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
696         if (!ctx->cmap->cols) {
697                 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
698                             _("Can't allocate colormap entries"));
699                 return FALSE;
700         }
701
702         p = ctx->in->data;
703         for (n = 0; n < ctx->cmap->size; n++) {
704                 if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
705                         guint16 col = p[0] + (p[1] << 8);
706                         ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
707                         ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
708                         ctx->cmap->cols[n].r = col << 3;
709                         p += 2;
710                 }
711                 else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
712                         ctx->cmap->cols[n].b = *p++;
713                         ctx->cmap->cols[n].g = *p++;
714                         ctx->cmap->cols[n].r = *p++;
715                         if (ctx->hdr->cmap_bpp == 32)
716                                 ctx->cmap->cols[n].a = *p++;
717                 } else {
718                         g_set_error(err, GDK_PIXBUF_ERROR, 
719                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
720                                     _("Unexpected bitdepth for colormap entries"));
721                         return FALSE;
722                 }
723         }
724         ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
725         if (!ctx->in)
726                 return FALSE;
727         return TRUE;
728 }
729
730 static gboolean try_preload(TGAContext *ctx, GError **err)
731 {
732         if (!ctx->hdr) {
733                 if (ctx->in->size >= sizeof(TGAHeader)) {
734                         ctx->hdr = g_try_malloc(sizeof(TGAHeader));
735                         if (!ctx->hdr) {
736                                 g_set_error(err, GDK_PIXBUF_ERROR,
737                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
738                                             _("Can't allocate TGA header memory"));
739                                 return FALSE;
740                         }
741                         g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
742                         ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
743 #ifdef DEBUG_TGA
744                         g_print ("infolen %d "
745                                  "has_cmap %d "
746                                  "type %d "
747                                  "cmap_start %d "
748                                  "cmap_n_colors %d "
749                                  "cmap_bpp %d "
750                                  "x %d y %d width %d height %d bpp %d "
751                                  "flags %#x",
752                                  ctx->hdr->infolen,
753                                  ctx->hdr->has_cmap,
754                                  ctx->hdr->type,
755                                  LE16(ctx->hdr->cmap_start),
756                                  LE16(ctx->hdr->cmap_n_colors),
757                                  ctx->hdr->cmap_bpp,
758                                  LE16(ctx->hdr->x_origin),
759                                  LE16(ctx->hdr->y_origin),
760                                  LE16(ctx->hdr->width),
761                                  LE16(ctx->hdr->height),
762                                  ctx->hdr->bpp,
763                                  ctx->hdr->flags);
764 #endif
765                         if (!ctx->in)
766                                 return FALSE;
767                         if (LE16(ctx->hdr->width) == 0 || 
768                             LE16(ctx->hdr->height) == 0) {
769                                 g_set_error(err, GDK_PIXBUF_ERROR,
770                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
771                                             _("TGA image has invalid dimensions"));
772                                 return FALSE;
773                         }
774                         if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
775                                 g_set_error(err, GDK_PIXBUF_ERROR, 
776                                             GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
777                                             _("TGA image type not supported"));
778                                 return FALSE;
779                         }
780                         switch (ctx->hdr->type) {
781                             case TGA_TYPE_PSEUDOCOLOR:
782                             case TGA_TYPE_RLE_PSEUDOCOLOR:
783                                     if (ctx->hdr->bpp != 8) {
784                                             g_set_error(err, GDK_PIXBUF_ERROR, 
785                                                         GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
786                                                         _("TGA image type not supported"));
787                                             return FALSE;
788                                     }
789                                     break;
790                             case TGA_TYPE_TRUECOLOR:
791                             case TGA_TYPE_RLE_TRUECOLOR:
792                                     if (ctx->hdr->bpp != 24 &&
793                                         ctx->hdr->bpp != 32) {
794                                             g_set_error(err, GDK_PIXBUF_ERROR, 
795                                                         GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
796                                                         _("TGA image type not supported"));
797                                             return FALSE;
798                                     }                         
799                                     break;
800                             case TGA_TYPE_GRAYSCALE:
801                             case TGA_TYPE_RLE_GRAYSCALE:
802                                     if (ctx->hdr->bpp != 8 &&
803                                         ctx->hdr->bpp != 16) {
804                                             g_set_error(err, GDK_PIXBUF_ERROR, 
805                                                         GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
806                                                         _("TGA image type not supported"));
807                                             return FALSE;
808                                     }
809                                     break;
810                             default:
811                                     g_set_error(err, GDK_PIXBUF_ERROR, 
812                                                 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
813                                                 _("TGA image type not supported"));
814                                     return FALSE;    
815                         }
816                         if (!fill_in_context(ctx, err))
817                                 return FALSE;
818                 } else {
819                         return TRUE;
820                 }
821         }
822         if (!ctx->skipped_info) {
823                 if (ctx->in->size >= ctx->hdr->infolen) {
824                         ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
825                         if (!ctx->in)
826                                 return FALSE;
827                         ctx->skipped_info = TRUE;
828                 } else {
829                         return TRUE;
830                 }
831         }
832         if (ctx->hdr->has_cmap && !ctx->cmap) {
833                 if (ctx->in->size >= ctx->cmap_size) {
834                         if (!try_colormap(ctx, err))
835                                 return FALSE;
836                 } else {
837                         return TRUE;
838                 }
839         }
840         if (!ctx->prepared) {
841                 if (ctx->pfunc)
842                         (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
843                 ctx->prepared = TRUE;
844         }
845         /* We shouldn't get here anyway. */
846         return TRUE;
847 }
848
849 static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
850                                            GdkPixbufModulePreparedFunc f1,
851                                            GdkPixbufModuleUpdatedFunc f2,
852                                            gpointer udata, GError **err)
853 {
854         TGAContext *ctx;
855
856         ctx = g_try_malloc(sizeof(TGAContext));
857         if (!ctx) {
858                 g_set_error(err, GDK_PIXBUF_ERROR, 
859                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
860                             _("Can't allocate memory for TGA context struct"));
861                 return NULL;
862         }
863
864         ctx->hdr = NULL;
865         ctx->rowstride = 0;
866         ctx->run_length_encoded = FALSE;
867
868         ctx->cmap = NULL;
869         ctx->cmap_size = 0;
870
871         ctx->pbuf = NULL;
872         ctx->pbuf_bytes = 0;
873         ctx->pbuf_bytes_done = 0;
874         ctx->pptr = NULL;
875
876         ctx->in = io_buffer_new(err);
877         if (!ctx->in) {
878                 g_free(ctx);
879                 return NULL;
880         }
881
882         ctx->skipped_info = FALSE;
883         ctx->prepared = FALSE;
884         ctx->done = FALSE;
885
886         ctx->sfunc = f0;
887         ctx->pfunc = f1;
888         ctx->ufunc = f2;
889         ctx->udata = udata;
890
891         return ctx;
892 }
893
894 static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
895                                                const guchar *buffer,
896                                                guint size,
897                                                GError **err)
898 {
899         TGAContext *ctx = (TGAContext*) data;
900         g_return_val_if_fail(ctx != NULL, FALSE);
901
902         if (ctx->done)
903                 return TRUE;
904
905         g_return_val_if_fail(buffer != NULL, TRUE);
906         ctx->in = io_buffer_append(ctx->in, buffer, size, err);
907         if (!ctx->in)
908                 return FALSE;
909         if (!ctx->prepared) {
910                 if (!try_preload(ctx, err))
911                         return FALSE;
912                 if (!ctx->prepared)
913                         return TRUE;
914                 if (ctx->in->size == 0)
915                         return TRUE;
916         }
917
918         if (ctx->run_length_encoded) {
919                 if (!parse_rle_data(ctx, err))
920                         return FALSE;
921         } else {
922                 while (ctx->in->size >= ctx->rowstride) {
923                         if (ctx->completed_lines >= ctx->pbuf->height) {
924                                 g_set_error(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
925                                             _("Excess data in file"));
926                                 return FALSE;
927                         }
928                         if (!parse_data_for_row(ctx, err))
929                                 return FALSE;
930                         ctx->completed_lines++;
931                 }
932         }
933
934         return TRUE;
935 }
936
937 static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
938 {
939         TGAContext *ctx = (TGAContext *) data;
940         g_return_val_if_fail(ctx != NULL, FALSE);
941
942         if (ctx->hdr)
943           g_free (ctx->hdr);
944         if (ctx->cmap) {
945           if (ctx->cmap->cols)
946             g_free (ctx->cmap->cols);
947           g_free (ctx->cmap);
948         }
949         if (ctx->pbuf)
950                 g_object_unref (ctx->pbuf);
951         if (ctx->in && ctx->in->size)
952                 ctx->in = io_buffer_free_segment (ctx->in, ctx->in->size, err);
953         if (!ctx->in) {
954                 g_free (ctx);
955                 return FALSE;
956         }
957         io_buffer_free (ctx->in);
958         g_free (ctx);
959         return TRUE;
960 }
961
962 void
963 MODULE_ENTRY (tga, fill_vtable) (GdkPixbufModule *module)
964 {
965         module->begin_load = gdk_pixbuf__tga_begin_load;
966         module->stop_load = gdk_pixbuf__tga_stop_load;
967         module->load_increment = gdk_pixbuf__tga_load_increment;
968 }
969
970 void
971 MODULE_ENTRY (tga, fill_info) (GdkPixbufFormat *info)
972 {
973         static GdkPixbufModulePattern signature[] = {
974                 { " \x1\x1", "x  ", 100 },
975                 { " \x1\x9", "x  ", 100 },
976                 { "  \x2", "xz ",  99 }, /* only 99 since .CUR also matches this */
977                 { "  \x3", "xz ", 100 },
978                 { "  \xa", "xz ", 100 },
979                 { "  \xb", "xz ", 100 },
980                 { NULL, NULL, 0 }
981         };
982         static gchar * mime_types[] = {
983                 "image/x-tga",
984                 NULL
985         };
986         static gchar * extensions[] = {
987                 "tga",
988                 "targa",
989                 NULL
990         };
991
992         info->name = "tga";
993         info->signature = signature;
994         info->description = N_("The Targa image format");
995         info->mime_types = mime_types;
996         info->extensions = extensions;
997         info->flags = 0;
998 }