]> Pileus Git - ~andy/gtk/blob - gdk-pixbuf/io-tga.c
Adds authentication support of CUPS backend
[~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         g_return_val_if_fail(ctx->cmap_size > 0, TRUE);
683
684         ctx->cmap = g_try_malloc(sizeof(TGAColormap));
685         if (!ctx->cmap) {
686                 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
687                                     _("Cannot allocate colormap structure"));
688                 return FALSE;
689         }
690         ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
691         ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
692         if (!ctx->cmap->cols) {
693                 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
694                                     _("Cannot allocate colormap entries"));
695                 return FALSE;
696         }
697
698         p = ctx->in->data;
699         for (n = 0; n < ctx->cmap->size; n++) {
700                 if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
701                         guint16 col = p[0] + (p[1] << 8);
702                         ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
703                         ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
704                         ctx->cmap->cols[n].r = col << 3;
705                         p += 2;
706                 }
707                 else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
708                         ctx->cmap->cols[n].b = *p++;
709                         ctx->cmap->cols[n].g = *p++;
710                         ctx->cmap->cols[n].r = *p++;
711                         if (ctx->hdr->cmap_bpp == 32)
712                                 ctx->cmap->cols[n].a = *p++;
713                 } else {
714                         g_set_error_literal(err, GDK_PIXBUF_ERROR, 
715                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
716                                             _("Unexpected bitdepth for colormap entries"));
717                         return FALSE;
718                 }
719         }
720         ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
721         if (!ctx->in)
722                 return FALSE;
723         return TRUE;
724 }
725
726 static gboolean try_preload(TGAContext *ctx, GError **err)
727 {
728         if (!ctx->hdr) {
729                 if (ctx->in->size >= sizeof(TGAHeader)) {
730                         ctx->hdr = g_try_malloc(sizeof(TGAHeader));
731                         if (!ctx->hdr) {
732                                 g_set_error_literal(err, GDK_PIXBUF_ERROR,
733                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
734                                                     _("Cannot allocate TGA header memory"));
735                                 return FALSE;
736                         }
737                         g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
738                         ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
739 #ifdef DEBUG_TGA
740                         g_print ("infolen %d "
741                                  "has_cmap %d "
742                                  "type %d "
743                                  "cmap_start %d "
744                                  "cmap_n_colors %d "
745                                  "cmap_bpp %d "
746                                  "x %d y %d width %d height %d bpp %d "
747                                  "flags %#x",
748                                  ctx->hdr->infolen,
749                                  ctx->hdr->has_cmap,
750                                  ctx->hdr->type,
751                                  LE16(ctx->hdr->cmap_start),
752                                  LE16(ctx->hdr->cmap_n_colors),
753                                  ctx->hdr->cmap_bpp,
754                                  LE16(ctx->hdr->x_origin),
755                                  LE16(ctx->hdr->y_origin),
756                                  LE16(ctx->hdr->width),
757                                  LE16(ctx->hdr->height),
758                                  ctx->hdr->bpp,
759                                  ctx->hdr->flags);
760 #endif
761                         if (!ctx->in)
762                                 return FALSE;
763                         if (LE16(ctx->hdr->width) == 0 || 
764                             LE16(ctx->hdr->height) == 0) {
765                                 g_set_error_literal(err, GDK_PIXBUF_ERROR,
766                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
767                                                     _("TGA image has invalid dimensions"));
768                                 return FALSE;
769                         }
770                         if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
771                                 g_set_error_literal(err, GDK_PIXBUF_ERROR, 
772                                                     GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
773                                                     _("TGA image type not supported"));
774                                 return FALSE;
775                         }
776                         switch (ctx->hdr->type) {
777                             case TGA_TYPE_PSEUDOCOLOR:
778                             case TGA_TYPE_RLE_PSEUDOCOLOR:
779                                     if (ctx->hdr->bpp != 8) {
780                                             g_set_error_literal(err, GDK_PIXBUF_ERROR, 
781                                                                 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
782                                                                 _("TGA image type not supported"));
783                                             return FALSE;
784                                     }
785                                     break;
786                             case TGA_TYPE_TRUECOLOR:
787                             case TGA_TYPE_RLE_TRUECOLOR:
788                                     if (ctx->hdr->bpp != 24 &&
789                                         ctx->hdr->bpp != 32) {
790                                             g_set_error_literal(err, GDK_PIXBUF_ERROR, 
791                                                                 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
792                                                                 _("TGA image type not supported"));
793                                             return FALSE;
794                                     }                         
795                                     break;
796                             case TGA_TYPE_GRAYSCALE:
797                             case TGA_TYPE_RLE_GRAYSCALE:
798                                     if (ctx->hdr->bpp != 8 &&
799                                         ctx->hdr->bpp != 16) {
800                                             g_set_error_literal(err, GDK_PIXBUF_ERROR, 
801                                                                 GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
802                                                                 _("TGA image type not supported"));
803                                             return FALSE;
804                                     }
805                                     break;
806                             default:
807                                     g_set_error_literal(err, GDK_PIXBUF_ERROR, 
808                                                         GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
809                                                         _("TGA image type not supported"));
810                                     return FALSE;    
811                         }
812                         if (!fill_in_context(ctx, err))
813                                 return FALSE;
814                 } else {
815                         return TRUE;
816                 }
817         }
818         if (!ctx->skipped_info) {
819                 if (ctx->in->size >= ctx->hdr->infolen) {
820                         ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
821                         if (!ctx->in)
822                                 return FALSE;
823                         ctx->skipped_info = TRUE;
824                 } else {
825                         return TRUE;
826                 }
827         }
828         if (ctx->hdr->has_cmap && !ctx->cmap) {
829                 if (ctx->in->size >= ctx->cmap_size) {
830                         if (!try_colormap(ctx, err))
831                                 return FALSE;
832                 } else {
833                         return TRUE;
834                 }
835         }
836         if (!ctx->prepared) {
837                 if (ctx->pfunc)
838                         (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
839                 ctx->prepared = TRUE;
840         }
841         /* We shouldn't get here anyway. */
842         return TRUE;
843 }
844
845 static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
846                                            GdkPixbufModulePreparedFunc f1,
847                                            GdkPixbufModuleUpdatedFunc f2,
848                                            gpointer udata, GError **err)
849 {
850         TGAContext *ctx;
851
852         ctx = g_try_malloc(sizeof(TGAContext));
853         if (!ctx) {
854                 g_set_error_literal(err, GDK_PIXBUF_ERROR, 
855                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
856                                     _("Cannot allocate memory for TGA context struct"));
857                 return NULL;
858         }
859
860         ctx->hdr = NULL;
861         ctx->rowstride = 0;
862         ctx->run_length_encoded = FALSE;
863
864         ctx->cmap = NULL;
865         ctx->cmap_size = 0;
866
867         ctx->pbuf = NULL;
868         ctx->pbuf_bytes = 0;
869         ctx->pbuf_bytes_done = 0;
870         ctx->pptr = NULL;
871
872         ctx->in = io_buffer_new(err);
873         if (!ctx->in) {
874                 g_free(ctx);
875                 return NULL;
876         }
877
878         ctx->skipped_info = FALSE;
879         ctx->prepared = FALSE;
880         ctx->done = FALSE;
881
882         ctx->sfunc = f0;
883         ctx->pfunc = f1;
884         ctx->ufunc = f2;
885         ctx->udata = udata;
886
887         return ctx;
888 }
889
890 static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
891                                                const guchar *buffer,
892                                                guint size,
893                                                GError **err)
894 {
895         TGAContext *ctx = (TGAContext*) data;
896         g_return_val_if_fail(ctx != NULL, FALSE);
897
898         if (ctx->done)
899                 return TRUE;
900
901         g_return_val_if_fail(buffer != NULL, TRUE);
902         ctx->in = io_buffer_append(ctx->in, buffer, size, err);
903         if (!ctx->in)
904                 return FALSE;
905         if (!ctx->prepared) {
906                 if (!try_preload(ctx, err))
907                         return FALSE;
908                 if (!ctx->prepared)
909                         return TRUE;
910                 if (ctx->in->size == 0)
911                         return TRUE;
912         }
913
914         if (ctx->run_length_encoded) {
915                 if (!parse_rle_data(ctx, err))
916                         return FALSE;
917         } else {
918                 while (ctx->in->size >= ctx->rowstride) {
919                         if (ctx->completed_lines >= ctx->pbuf->height) {
920                                 g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
921                                                     _("Excess data in file"));
922                                 return FALSE;
923                         }
924                         if (!parse_data_for_row(ctx, err))
925                                 return FALSE;
926                         ctx->completed_lines++;
927                 }
928         }
929
930         return TRUE;
931 }
932
933 static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
934 {
935         TGAContext *ctx = (TGAContext *) data;
936         g_return_val_if_fail(ctx != NULL, FALSE);
937
938         if (ctx->hdr &&
939             (ctx->hdr->flags & TGA_ORIGIN_UPPER) == 0 && 
940             ctx->run_length_encoded && 
941             ctx->pbuf) {
942                 pixbuf_flip_vertically (ctx->pbuf);
943                 if (ctx->ufunc)
944                         (*ctx->ufunc) (ctx->pbuf, 0, 0,
945                                        ctx->pbuf->width, ctx->pbuf->height,
946                                        ctx->udata);
947         }
948         g_free (ctx->hdr);
949         if (ctx->cmap) {
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(function) G_MODULE_EXPORT void function
968 #else
969 #define MODULE_ENTRY(function) void _gdk_pixbuf__tga_ ## function
970 #endif
971
972 MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
973 {
974         module->begin_load = gdk_pixbuf__tga_begin_load;
975         module->stop_load = gdk_pixbuf__tga_stop_load;
976         module->load_increment = gdk_pixbuf__tga_load_increment;
977 }
978
979 MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
980 {
981         static GdkPixbufModulePattern signature[] = {
982                 { " \x1\x1", "x  ", 100 },
983                 { " \x1\x9", "x  ", 100 },
984                 { "  \x2", "xz ",  99 }, /* only 99 since .CUR also matches this */
985                 { "  \x3", "xz ", 100 },
986                 { "  \xa", "xz ", 100 },
987                 { "  \xb", "xz ", 100 },
988                 { NULL, NULL, 0 }
989         };
990         static gchar * mime_types[] = {
991                 "image/x-tga",
992                 NULL
993         };
994         static gchar * extensions[] = {
995                 "tga",
996                 "targa",
997                 NULL
998         };
999
1000         info->name = "tga";
1001         info->signature = signature;
1002         info->description = N_("The Targa image format");
1003         info->mime_types = mime_types;
1004         info->extensions = extensions;
1005         info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
1006         info->license = "LGPL";
1007 }