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