]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-tga.c
[quartz] Delete the typedef of GdkDevicePrivate
[~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_literal(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_literal(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_literal(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_literal(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         g_free(buffer->data);
232         g_free(buffer);
233 }
234
235 static void free_buffer(guchar *pixels, gpointer data)
236 {
237         g_free(pixels);
238 }
239
240 static GdkPixbuf *get_contiguous_pixbuf (guint width, 
241                                          guint height, 
242                                          gboolean has_alpha)
243 {
244         guchar *pixels;
245         guint channels, rowstride, bytes;
246         
247         if (has_alpha) 
248                 channels = 4;
249         else 
250                 channels = 3;
251         
252         rowstride = width * channels;
253         
254         if (rowstride / channels != width)
255                 return NULL;                
256
257         bytes = height * rowstride;
258
259         if (bytes / rowstride != height)
260                 return NULL;                
261
262         pixels = g_try_malloc (bytes);
263
264         if (!pixels)
265                 return NULL;
266         
267         return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, has_alpha, 8,
268                                          width, height, rowstride, free_buffer, NULL);
269 }
270
271 static void pixbuf_flip_row (GdkPixbuf *pixbuf, guchar *ph)
272 {
273         guchar *p, *s;
274         guchar tmp;
275         gint count;
276
277         p = ph;
278         s = p + pixbuf->n_channels * (pixbuf->width - 1);
279         while (p < s) {
280                 for (count = pixbuf->n_channels; count > 0; count--, p++, s++) {
281                         tmp = *p;
282                         *p = *s;
283                         *s = tmp;
284                 }
285                 s -= 2 * pixbuf->n_channels;
286         }               
287 }
288
289 static void pixbuf_flip_vertically (GdkPixbuf *pixbuf)
290 {
291         guchar *ph, *sh, *p, *s;
292         guchar tmp;
293         gint count;
294
295         ph = pixbuf->pixels;
296         sh = pixbuf->pixels + pixbuf->height*pixbuf->rowstride;
297         while (ph < sh - pixbuf->rowstride) {
298                 p = ph;
299                 s = sh - pixbuf->rowstride;
300                 for (count = pixbuf->n_channels * pixbuf->width; count > 0; count--, p++, s++) {
301                         tmp = *p;
302                         *p = *s;
303                         *s = tmp;
304                 }
305                 sh -= pixbuf->rowstride;
306                 ph += pixbuf->rowstride;
307         }
308 }
309
310 static gboolean fill_in_context(TGAContext *ctx, GError **err)
311 {
312         gboolean alpha;
313         guint w, h;
314
315         g_return_val_if_fail(ctx != NULL, FALSE);
316
317         ctx->run_length_encoded =
318                 ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
319                  || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
320                  || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE));
321
322         if (ctx->hdr->has_cmap)
323                 ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
324                         LE16(ctx->hdr->cmap_n_colors);
325
326         alpha = ((ctx->hdr->bpp == 16) || 
327                  (ctx->hdr->bpp == 32) ||
328                  (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
329
330         w = LE16(ctx->hdr->width);
331         h = LE16(ctx->hdr->height);
332
333         if (ctx->sfunc) {
334                 gint wi = w;
335                 gint hi = h;
336                 
337                 (*ctx->sfunc) (&wi, &hi, ctx->udata);
338                 
339                 if (wi == 0 || hi == 0) 
340                         return FALSE;
341         }
342
343         ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
344
345         if (!ctx->pbuf) {
346                 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
347                                     _("Cannot allocate new pixbuf"));
348                 return FALSE;
349         }
350
351         ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
352         if ((ctx->hdr->flags & TGA_ORIGIN_UPPER) || ctx->run_length_encoded)
353                 ctx->pptr = ctx->pbuf->pixels;
354         else
355                 ctx->pptr = ctx->pbuf->pixels + (ctx->pbuf->height - 1)*ctx->pbuf->rowstride;
356
357         if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
358           ctx->rowstride = ctx->pbuf->width;
359         else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
360           ctx->rowstride = (alpha ? ctx->pbuf->width * 2 : ctx->pbuf->width);
361         else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
362                 ctx->rowstride = ctx->pbuf->rowstride;
363
364         ctx->completed_lines = 0;
365         return TRUE;
366 }
367
368 static void parse_data_for_row_pseudocolor(TGAContext *ctx)
369 {
370         guchar *s = ctx->in->data;
371         guint upper_bound = ctx->pbuf->width;
372         guchar *p = ctx->pptr;
373
374         for (; upper_bound; upper_bound--, s++) {
375                 *p++ = ctx->cmap->cols[*s].r;
376                 *p++ = ctx->cmap->cols[*s].g;
377                 *p++ = ctx->cmap->cols[*s].b;
378                 if (ctx->hdr->cmap_bpp == 32)
379                         *p++ = ctx->cmap->cols[*s].a;
380         }
381 }
382
383 static void swap_channels(TGAContext *ctx)
384 {
385         guchar swap;
386         guint count;
387         guchar *p = ctx->pptr;
388         for (count = ctx->pbuf->width; count; count--) {
389           swap = p[0];
390           p[0] = p[2];
391           p[2] = swap;
392           p += ctx->pbuf->n_channels;
393         }
394 }
395
396 static void parse_data_for_row_truecolor(TGAContext *ctx)
397 {
398         g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
399         swap_channels(ctx);
400 }
401
402 static void parse_data_for_row_grayscale(TGAContext *ctx)
403 {
404         guchar *s = ctx->in->data;
405         guint upper_bound = ctx->pbuf->width;
406
407         guchar *p = ctx->pptr;
408         for (; upper_bound; upper_bound--) {
409                 p[0] = p[1] = p[2] = *s++;
410                 if (ctx->pbuf->n_channels == 4)
411                   p[3] = *s++;
412                 p += ctx->pbuf->n_channels;
413         }
414 }
415
416 static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
417 {
418         guint row;
419
420         if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
421                 parse_data_for_row_pseudocolor(ctx);
422         else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
423                 parse_data_for_row_truecolor(ctx);
424         else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
425                 parse_data_for_row_grayscale(ctx);
426
427         if (ctx->hdr->flags & TGA_ORIGIN_RIGHT)
428                 pixbuf_flip_row (ctx->pbuf, ctx->pptr);
429         if (ctx->hdr->flags & TGA_ORIGIN_UPPER)
430                 ctx->pptr += ctx->pbuf->rowstride;
431         else
432                 ctx->pptr -= ctx->pbuf->rowstride;
433         ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
434         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
435                 ctx->done = TRUE;
436         
437         ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err);
438         if (!ctx->in)
439                 return FALSE;
440         row = (ctx->pptr - ctx->pbuf->pixels) / ctx->pbuf->rowstride - 1;
441         if (ctx->ufunc)
442                 (*ctx->ufunc) (ctx->pbuf, 0, row, ctx->pbuf->width, 1, ctx->udata);
443         return TRUE;
444 }
445
446 static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
447 {
448         for (; *rle_count; (*rle_count)--) {
449                 g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
450                 ctx->pptr += ctx->pbuf->n_channels;
451                 ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
452                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
453                         return;
454         }
455 }
456
457 static guint parse_rle_data_pseudocolor(TGAContext *ctx)
458 {
459         guint rle_num, raw_num;
460         guchar *s, tag;
461         guint n;
462
463         g_return_val_if_fail(ctx->in->size > 0, 0);
464         s = ctx->in->data;
465
466         for (n = 0; n < ctx->in->size; ) {
467                 tag = *s;
468                 s++, n++;
469                 if (tag & 0x80) {
470                         if (n == ctx->in->size) {
471                                 return --n;
472                         } else {
473                                 rle_num = (tag & 0x7f) + 1;
474                                 write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
475                                 s++, n++;
476                                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
477                                         ctx->done = TRUE;
478                                         return n;
479                                 }
480                         }
481                 } else {
482                         raw_num = tag + 1;
483                         if (n + raw_num >= ctx->in->size) {
484                                 return --n;
485                         } else {
486                                 for (; raw_num; raw_num--) {
487                                         *ctx->pptr++ =
488                                                 ctx->cmap->cols[*s].r;
489                                         *ctx->pptr++ =
490                                                 ctx->cmap->cols[*s].g;
491                                         *ctx->pptr++ =
492                                                 ctx->cmap->cols[*s].b;
493                                         if (ctx->pbuf->n_channels == 4)
494                                                 *ctx->pptr++ = ctx->cmap->cols[*s].a;
495                                         s++, n++;
496                                         ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
497                                         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
498                                                 ctx->done = TRUE;
499                                                 return n;
500                                         }
501                                 }
502                         }
503                 }
504         }
505
506         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) 
507                 ctx->done = TRUE;
508         
509         return n;
510 }
511
512 static guint parse_rle_data_truecolor(TGAContext *ctx)
513 {
514         TGAColor col;
515         guint rle_num, raw_num;
516         guchar *s, tag;
517         guint n = 0;
518
519         g_return_val_if_fail(ctx->in->size > 0, 0);
520         s = ctx->in->data;
521
522         for (n = 0; n < ctx->in->size; ) {
523                 tag = *s;
524                 s++, n++;
525                 if (tag & 0x80) {
526                         if (n + ctx->pbuf->n_channels >= ctx->in->size) {
527                                 return --n;
528                         } else {
529                                 rle_num = (tag & 0x7f) + 1;
530                                 col.b = *s++;
531                                 col.g = *s++;
532                                 col.r = *s++;
533                                 if (ctx->hdr->bpp == 32)
534                                         col.a = *s++;
535                                 n += ctx->pbuf->n_channels;
536                                 write_rle_data(ctx, &col, &rle_num);
537                                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
538                                         ctx->done = TRUE;
539                                         return n;
540                                 }
541                         }
542                 } else {
543                         raw_num = tag + 1;
544                         if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
545                                 return --n;
546                         } else {
547                                 for (; raw_num; raw_num--) {
548                                         ctx->pptr[2] = *s++;
549                                         ctx->pptr[1] = *s++;
550                                         ctx->pptr[0] = *s++;
551                                         if (ctx->hdr->bpp == 32)
552                                                 ctx->pptr[3] = *s++;
553                                         n += ctx->pbuf->n_channels;
554                                         ctx->pptr += ctx->pbuf->n_channels;
555                                         ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
556                                         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
557                                                 ctx->done = TRUE;
558                                                 return n;
559                                         }
560                                 }
561                                 
562                                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
563                                         ctx->done = TRUE;
564                                         return n;
565                                 }
566                         }
567                 }
568         }
569         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
570                 ctx->done = TRUE;
571         return n;
572 }
573
574 static guint parse_rle_data_grayscale(TGAContext *ctx)
575 {
576         TGAColor tone;
577         guint rle_num, raw_num;
578         guchar *s, tag;
579         guint n;
580
581         g_return_val_if_fail(ctx->in->size > 0, 0);
582         s = ctx->in->data;
583
584         for (n = 0; n < ctx->in->size; ) {
585                 tag = *s;
586                 s++, n++;
587                 if (tag & 0x80) {
588                         if (n + (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
589                                 return --n;
590                         } else {
591                                 rle_num = (tag & 0x7f) + 1;
592                                 tone.r = tone.g = tone.b = *s;
593                                 s++, n++;
594                                 if (ctx->pbuf->n_channels == 4) {
595                                         tone.a = *s++;
596                                         n++;
597                                 }
598                                 write_rle_data(ctx, &tone, &rle_num);
599                                 if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
600                                         ctx->done = TRUE;
601                                         return n;
602                                 }
603                         }
604                 } else {
605                         raw_num = tag + 1;
606                         if (n + raw_num * (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
607                                 return --n;
608                         } else {
609                                 for (; raw_num; raw_num--) {
610                                         ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
611                                         s++, n++;
612                                         if (ctx->pbuf->n_channels == 4) {
613                                                 ctx->pptr[3] = *s++;
614                                                 n++;
615                                         }
616                                         ctx->pptr += ctx->pbuf->n_channels;
617                                         ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
618                                         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
619                                                 ctx->done = TRUE;
620                                                 return n;
621                                         }
622                                 }
623                         }
624                 }
625         }
626         if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
627                 ctx->done = TRUE;
628         return n;
629 }
630
631 static gboolean parse_rle_data(TGAContext *ctx, GError **err)
632 {
633         guint rows = 0;
634         guint count = 0;
635         guint bytes_done_before = ctx->pbuf_bytes_done;
636
637         if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
638                 count = parse_rle_data_pseudocolor(ctx);
639         else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
640                 count = parse_rle_data_truecolor(ctx);
641         else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE)
642                 count = parse_rle_data_grayscale(ctx);
643
644         if (ctx->hdr->flags & TGA_ORIGIN_RIGHT) {
645                 guchar *row = ctx->pbuf->pixels + (bytes_done_before / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
646                 guchar *row_after = ctx->pbuf->pixels + (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
647                 for (; row < row_after; row += ctx->pbuf->rowstride)
648                         pixbuf_flip_row (ctx->pbuf, row);
649         }
650
651         ctx->in = io_buffer_free_segment(ctx->in, count, err);
652         if (!ctx->in)
653                 return FALSE;
654
655         if (ctx->done) {
656                 /* FIXME doing the vertical flipping afterwards is not
657                  * perfect, but doing it during the rle decoding in place
658                  * is considerably more work. 
659                  */
660                 if (!(ctx->hdr->flags & TGA_ORIGIN_UPPER)) {
661                         pixbuf_flip_vertically (ctx->pbuf);
662                         ctx->hdr->flags |= TGA_ORIGIN_UPPER;
663                 }
664
665         }
666                 
667         rows = ctx->pbuf_bytes_done / ctx->pbuf->rowstride - bytes_done_before / ctx->pbuf->rowstride;
668         if (ctx->ufunc)
669                 (*ctx->ufunc) (ctx->pbuf, 0, bytes_done_before / ctx->pbuf->rowstride,
670                                ctx->pbuf->width, rows,
671                                ctx->udata);
672
673         return TRUE;
674 }
675
676 static gboolean try_colormap(TGAContext *ctx, GError **err)
677 {
678         static guchar *p;
679         static guint n;
680
681         g_return_val_if_fail(ctx != NULL, FALSE);
682
683         if (ctx->cmap_size == 0) {
684                 g_set_error_literal(err, GDK_PIXBUF_ERROR,
685                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
686                                     _("Image is corrupted or truncated"));
687                         return FALSE;
688         }
689
690         ctx->cmap = g_try_malloc(sizeof(TGAColormap));
691         if (!ctx->cmap) {
692                 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
693                                     _("Cannot allocate colormap structure"));
694                 return FALSE;
695         }
696         ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
697         ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
698         if (!ctx->cmap->cols) {
699                 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
700                                     _("Cannot allocate colormap entries"));
701                 return FALSE;
702         }
703
704         p = ctx->in->data;
705         for (n = 0; n < ctx->cmap->size; n++) {
706                 if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
707                         guint16 col = p[0] + (p[1] << 8);
708                         ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
709                         ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
710                         ctx->cmap->cols[n].r = col << 3;
711                         p += 2;
712                 }
713                 else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
714                         ctx->cmap->cols[n].b = *p++;
715                         ctx->cmap->cols[n].g = *p++;
716                         ctx->cmap->cols[n].r = *p++;
717                         if (ctx->hdr->cmap_bpp == 32)
718                                 ctx->cmap->cols[n].a = *p++;
719                 } else {
720                         g_set_error_literal(err, GDK_PIXBUF_ERROR, 
721                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
722                                             _("Unexpected bitdepth for colormap entries"));
723                         return FALSE;
724                 }
725         }
726         ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
727         if (!ctx->in)
728                 return FALSE;
729         return TRUE;
730 }
731
732 static gboolean try_preload(TGAContext *ctx, GError **err)
733 {
734         if (!ctx->hdr) {
735                 if (ctx->in->size >= sizeof(TGAHeader)) {
736                         ctx->hdr = g_try_malloc(sizeof(TGAHeader));
737                         if (!ctx->hdr) {
738                                 g_set_error_literal(err, GDK_PIXBUF_ERROR,
739                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
740                                                     _("Cannot allocate TGA header memory"));
741                                 return FALSE;
742                         }
743                         g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
744                         ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
745 #ifdef DEBUG_TGA
746                         g_print ("infolen %d "
747                                  "has_cmap %d "
748                                  "type %d "
749                                  "cmap_start %d "
750                                  "cmap_n_colors %d "
751                                  "cmap_bpp %d "
752                                  "x %d y %d width %d height %d bpp %d "
753                                  "flags %#x",
754                                  ctx->hdr->infolen,
755                                  ctx->hdr->has_cmap,
756                                  ctx->hdr->type,
757                                  LE16(ctx->hdr->cmap_start),
758                                  LE16(ctx->hdr->cmap_n_colors),
759                                  ctx->hdr->cmap_bpp,
760                                  LE16(ctx->hdr->x_origin),
761                                  LE16(ctx->hdr->y_origin),
762                                  LE16(ctx->hdr->width),
763                                  LE16(ctx->hdr->height),
764                                  ctx->hdr->bpp,
765                                  ctx->hdr->flags);
766 #endif
767                         if (!ctx->in)
768                                 return FALSE;
769                         if (LE16(ctx->hdr->width) == 0 || 
770                             LE16(ctx->hdr->height) == 0) {
771                                 g_set_error_literal(err, GDK_PIXBUF_ERROR,
772                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
773                                                     _("TGA image has invalid dimensions"));
774                                 return FALSE;
775                         }
776                         if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
777                                 g_set_error_literal(err, GDK_PIXBUF_ERROR, 
778                                                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
779                                                     _("TGA image type not supported"));
780                                 return FALSE;
781                         }
782                         switch (ctx->hdr->type) {
783                             case TGA_TYPE_PSEUDOCOLOR:
784                             case TGA_TYPE_RLE_PSEUDOCOLOR:
785                                     if (ctx->hdr->bpp != 8) {
786                                             g_set_error_literal(err, GDK_PIXBUF_ERROR, 
787                                                                 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
788                                                                 _("TGA image type not supported"));
789                                             return FALSE;
790                                     }
791                                     break;
792                             case TGA_TYPE_TRUECOLOR:
793                             case TGA_TYPE_RLE_TRUECOLOR:
794                                     if (ctx->hdr->bpp != 24 &&
795                                         ctx->hdr->bpp != 32) {
796                                             g_set_error_literal(err, GDK_PIXBUF_ERROR, 
797                                                                 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
798                                                                 _("TGA image type not supported"));
799                                             return FALSE;
800                                     }                         
801                                     break;
802                             case TGA_TYPE_GRAYSCALE:
803                             case TGA_TYPE_RLE_GRAYSCALE:
804                                     if (ctx->hdr->bpp != 8 &&
805                                         ctx->hdr->bpp != 16) {
806                                             g_set_error_literal(err, GDK_PIXBUF_ERROR, 
807                                                                 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
808                                                                 _("TGA image type not supported"));
809                                             return FALSE;
810                                     }
811                                     break;
812                             default:
813                                     g_set_error_literal(err, GDK_PIXBUF_ERROR, 
814                                                         GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
815                                                         _("TGA image type not supported"));
816                                     return FALSE;    
817                         }
818                         if (!fill_in_context(ctx, err))
819                                 return FALSE;
820                 } else {
821                         return TRUE;
822                 }
823         }
824         if (!ctx->skipped_info) {
825                 if (ctx->in->size >= ctx->hdr->infolen) {
826                         ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
827                         if (!ctx->in)
828                                 return FALSE;
829                         ctx->skipped_info = TRUE;
830                 } else {
831                         return TRUE;
832                 }
833         }
834         if (ctx->hdr->has_cmap && !ctx->cmap) {
835                 if (ctx->in->size >= ctx->cmap_size) {
836                         if (!try_colormap(ctx, err))
837                                 return FALSE;
838                 } else {
839                         return TRUE;
840                 }
841         }
842         if (!ctx->prepared) {
843                 if (ctx->pfunc)
844                         (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
845                 ctx->prepared = TRUE;
846         }
847         /* We shouldn't get here anyway. */
848         return TRUE;
849 }
850
851 static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
852                                            GdkPixbufModulePreparedFunc f1,
853                                            GdkPixbufModuleUpdatedFunc f2,
854                                            gpointer udata, GError **err)
855 {
856         TGAContext *ctx;
857
858         ctx = g_try_malloc(sizeof(TGAContext));
859         if (!ctx) {
860                 g_set_error_literal(err, GDK_PIXBUF_ERROR, 
861                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
862                                     _("Cannot allocate memory for TGA context struct"));
863                 return NULL;
864         }
865
866         ctx->hdr = NULL;
867         ctx->rowstride = 0;
868         ctx->run_length_encoded = FALSE;
869
870         ctx->cmap = NULL;
871         ctx->cmap_size = 0;
872
873         ctx->pbuf = NULL;
874         ctx->pbuf_bytes = 0;
875         ctx->pbuf_bytes_done = 0;
876         ctx->pptr = NULL;
877
878         ctx->in = io_buffer_new(err);
879         if (!ctx->in) {
880                 g_free(ctx);
881                 return NULL;
882         }
883
884         ctx->skipped_info = FALSE;
885         ctx->prepared = FALSE;
886         ctx->done = FALSE;
887
888         ctx->sfunc = f0;
889         ctx->pfunc = f1;
890         ctx->ufunc = f2;
891         ctx->udata = udata;
892
893         return ctx;
894 }
895
896 static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
897                                                const guchar *buffer,
898                                                guint size,
899                                                GError **err)
900 {
901         TGAContext *ctx = (TGAContext*) data;
902         g_return_val_if_fail(ctx != NULL, FALSE);
903
904         if (ctx->done)
905                 return TRUE;
906
907         g_return_val_if_fail(buffer != NULL, TRUE);
908         ctx->in = io_buffer_append(ctx->in, buffer, size, err);
909         if (!ctx->in)
910                 return FALSE;
911         if (!ctx->prepared) {
912                 if (!try_preload(ctx, err))
913                         return FALSE;
914                 if (!ctx->prepared)
915                         return TRUE;
916                 if (ctx->in->size == 0)
917                         return TRUE;
918         }
919
920         if (ctx->run_length_encoded) {
921                 if (!parse_rle_data(ctx, err))
922                         return FALSE;
923         } else {
924                 while (ctx->in->size >= ctx->rowstride) {
925                         if (ctx->completed_lines >= ctx->pbuf->height) {
926                                 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
927                                                     _("Excess data in file"));
928                                 return FALSE;
929                         }
930                         if (!parse_data_for_row(ctx, err))
931                                 return FALSE;
932                         ctx->completed_lines++;
933                 }
934         }
935
936         return TRUE;
937 }
938
939 static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
940 {
941         TGAContext *ctx = (TGAContext *) data;
942         g_return_val_if_fail(ctx != NULL, FALSE);
943
944         if (ctx->hdr &&
945             (ctx->hdr->flags & TGA_ORIGIN_UPPER) == 0 && 
946             ctx->run_length_encoded && 
947             ctx->pbuf) {
948                 pixbuf_flip_vertically (ctx->pbuf);
949                 if (ctx->ufunc)
950                         (*ctx->ufunc) (ctx->pbuf, 0, 0,
951                                        ctx->pbuf->width, ctx->pbuf->height,
952                                        ctx->udata);
953         }
954         g_free (ctx->hdr);
955         if (ctx->cmap) {
956           g_free (ctx->cmap->cols);
957           g_free (ctx->cmap);
958         }
959         if (ctx->pbuf)
960                 g_object_unref (ctx->pbuf);
961         if (ctx->in && ctx->in->size)
962                 ctx->in = io_buffer_free_segment (ctx->in, ctx->in->size, err);
963         if (!ctx->in) {
964                 g_free (ctx);
965                 return FALSE;
966         }
967         io_buffer_free (ctx->in);
968         g_free (ctx);
969         return TRUE;
970 }
971
972 #ifndef INCLUDE_tga
973 #define MODULE_ENTRY(function) G_MODULE_EXPORT void function
974 #else
975 #define MODULE_ENTRY(function) void _gdk_pixbuf__tga_ ## function
976 #endif
977
978 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
979 {
980         module->begin_load = gdk_pixbuf__tga_begin_load;
981         module->stop_load = gdk_pixbuf__tga_stop_load;
982         module->load_increment = gdk_pixbuf__tga_load_increment;
983 }
984
985 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
986 {
987         static GdkPixbufModulePattern signature[] = {
988                 { " \x1\x1", "x  ", 100 },
989                 { " \x1\x9", "x  ", 100 },
990                 { "  \x2", "xz ",  99 }, /* only 99 since .CUR also matches this */
991                 { "  \x3", "xz ", 100 },
992                 { "  \xa", "xz ", 100 },
993                 { "  \xb", "xz ", 100 },
994                 { NULL, NULL, 0 }
995         };
996         static gchar * mime_types[] = {
997                 "image/x-tga",
998                 NULL
999         };
1000         static gchar * extensions[] = {
1001                 "tga",
1002                 "targa",
1003                 NULL
1004         };
1005
1006         info->name = "tga";
1007         info->signature = signature;
1008         info->description = N_("The Targa image format");
1009         info->mime_types = mime_types;
1010         info->extensions = extensions;
1011         info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
1012         info->license = "LGPL";
1013 }