summaryrefslogtreecommitdiff
path: root/gdk-pixbuf/io-tga.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdk-pixbuf/io-tga.c')
-rw-r--r--gdk-pixbuf/io-tga.c1013
1 files changed, 0 insertions, 1013 deletions
diff --git a/gdk-pixbuf/io-tga.c b/gdk-pixbuf/io-tga.c
deleted file mode 100644
index 0391e1eec9..0000000000
--- a/gdk-pixbuf/io-tga.c
+++ /dev/null
@@ -1,1013 +0,0 @@
-/* -*- mode: C; c-file-style: "linux" -*- */
-/*
- * GdkPixbuf library - TGA image loader
- * Copyright (C) 1999 Nicola Girardi <nikke@swlibero.org>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- *
- */
-
-/*
- * Some NOTES about the TGA loader (2001/06/07, nikke@swlibero.org)
- *
- * - The TGAFooter isn't present in all TGA files. In fact, there's an older
- * format specification, still in use, which doesn't cover the TGAFooter.
- * Actually, most TGA files I have are of the older type. Anyway I put the
- * struct declaration here for completeness.
- *
- * - Error handling was designed to be very paranoid.
- */
-
-#include "config.h"
-#include <stdio.h>
-#include <string.h>
-
-#include "gdk-pixbuf-private.h"
-#include "gdk-pixbuf-io.h"
-
-#undef DEBUG_TGA
-
-#define TGA_INTERLEAVE_MASK 0xc0
-#define TGA_INTERLEAVE_NONE 0x00
-#define TGA_INTERLEAVE_2WAY 0x40
-#define TGA_INTERLEAVE_4WAY 0x80
-
-#define TGA_ORIGIN_MASK 0x30
-#define TGA_ORIGIN_RIGHT 0x10
-#define TGA_ORIGIN_UPPER 0x20
-
-enum {
- TGA_TYPE_NODATA = 0,
- TGA_TYPE_PSEUDOCOLOR = 1,
- TGA_TYPE_TRUECOLOR = 2,
- TGA_TYPE_GRAYSCALE = 3,
- TGA_TYPE_RLE_PSEUDOCOLOR = 9,
- TGA_TYPE_RLE_TRUECOLOR = 10,
- TGA_TYPE_RLE_GRAYSCALE = 11
-};
-
-#define LE16(p) ((p)[0] + ((p)[1] << 8))
-
-typedef struct _IOBuffer IOBuffer;
-
-typedef struct _TGAHeader TGAHeader;
-typedef struct _TGAFooter TGAFooter;
-
-typedef struct _TGAColormap TGAColormap;
-typedef struct _TGAColor TGAColor;
-
-typedef struct _TGAContext TGAContext;
-
-struct _TGAHeader {
- guint8 infolen;
- guint8 has_cmap;
- guint8 type;
-
- guint8 cmap_start[2];
- guint8 cmap_n_colors[2];
- guint8 cmap_bpp;
-
- guint8 x_origin[2];
- guint8 y_origin[2];
-
- guint8 width[2];
- guint8 height[2];
- guint8 bpp;
-
- guint8 flags;
-};
-
-struct _TGAFooter {
- guint32 extension_area_offset;
- guint32 developer_directory_offset;
-
- /* Standard TGA signature, "TRUEVISION-XFILE.\0". */
- union {
- gchar sig_full[18];
- struct {
- gchar sig_chunk[16];
- gchar dot, null;
- } sig_struct;
- } sig;
-};
-
-struct _TGAColormap {
- gint size;
- TGAColor *cols;
-};
-
-struct _TGAColor {
- guchar r, g, b, a;
-};
-
-struct _TGAContext {
- TGAHeader *hdr;
- guint rowstride;
- guint completed_lines;
- gboolean run_length_encoded;
-
- TGAColormap *cmap;
- guint cmap_size;
-
- GdkPixbuf *pbuf;
- guint pbuf_bytes;
- guint pbuf_bytes_done;
- guchar *pptr;
-
- IOBuffer *in;
-
- gboolean skipped_info;
- gboolean prepared;
- gboolean done;
-
- GdkPixbufModuleSizeFunc sfunc;
- GdkPixbufModulePreparedFunc pfunc;
- GdkPixbufModuleUpdatedFunc ufunc;
- gpointer udata;
-};
-
-struct _IOBuffer {
- guchar *data;
- guint size;
-};
-
-static IOBuffer *io_buffer_new(GError **err)
-{
- IOBuffer *buffer;
- buffer = g_try_malloc(sizeof(IOBuffer));
- if (!buffer) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot allocate memory for IOBuffer struct"));
- return NULL;
- }
- buffer->data = NULL;
- buffer->size = 0;
- return buffer;
-}
-
-static IOBuffer *io_buffer_append(IOBuffer *buffer,
- const guchar *data, guint len,
- GError **err)
-{
- if (!buffer)
- return NULL;
- if (!buffer->data) {
- buffer->data = g_try_malloc(len);
- if (!buffer->data) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot allocate memory for IOBuffer data"));
- g_free(buffer);
- return NULL;
- }
- g_memmove(buffer->data, data, len);
- buffer->size = len;
- } else {
- guchar *tmp = g_try_realloc (buffer->data, buffer->size + len);
- if (!tmp) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot realloc IOBuffer data"));
- g_free(buffer);
- return NULL;
- }
- buffer->data = tmp;
- g_memmove(&buffer->data[buffer->size], data, len);
- buffer->size += len;
- }
- return buffer;
-}
-
-static IOBuffer *io_buffer_free_segment(IOBuffer *buffer,
- guint count,
- GError **err)
-{
- g_return_val_if_fail(buffer != NULL, NULL);
- g_return_val_if_fail(buffer->data != NULL, NULL);
- if (count == buffer->size) {
- g_free(buffer->data);
- buffer->data = NULL;
- buffer->size = 0;
- } else {
- guchar *new_buf;
- guint new_size;
-
- new_size = buffer->size - count;
- new_buf = g_try_malloc(new_size);
- if (!new_buf) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot allocate temporary IOBuffer data"));
- g_free(buffer->data);
- g_free(buffer);
- return NULL;
- }
-
- g_memmove(new_buf, &buffer->data[count], new_size);
- g_free(buffer->data);
- buffer->data = new_buf;
- buffer->size = new_size;
- }
- return buffer;
-}
-
-static void io_buffer_free(IOBuffer *buffer)
-{
- g_return_if_fail(buffer != NULL);
- g_free(buffer->data);
- g_free(buffer);
-}
-
-static void free_buffer(guchar *pixels, gpointer data)
-{
- g_free(pixels);
-}
-
-static GdkPixbuf *get_contiguous_pixbuf (guint width,
- guint height,
- gboolean has_alpha)
-{
- guchar *pixels;
- guint channels, rowstride, bytes;
-
- if (has_alpha)
- channels = 4;
- else
- channels = 3;
-
- rowstride = width * channels;
-
- if (rowstride / channels != width)
- return NULL;
-
- bytes = height * rowstride;
-
- if (bytes / rowstride != height)
- return NULL;
-
- pixels = g_try_malloc (bytes);
-
- if (!pixels)
- return NULL;
-
- return gdk_pixbuf_new_from_data (pixels, GDK_COLORSPACE_RGB, has_alpha, 8,
- width, height, rowstride, free_buffer, NULL);
-}
-
-static void pixbuf_flip_row (GdkPixbuf *pixbuf, guchar *ph)
-{
- guchar *p, *s;
- guchar tmp;
- gint count;
-
- p = ph;
- s = p + pixbuf->n_channels * (pixbuf->width - 1);
- while (p < s) {
- for (count = pixbuf->n_channels; count > 0; count--, p++, s++) {
- tmp = *p;
- *p = *s;
- *s = tmp;
- }
- s -= 2 * pixbuf->n_channels;
- }
-}
-
-static void pixbuf_flip_vertically (GdkPixbuf *pixbuf)
-{
- guchar *ph, *sh, *p, *s;
- guchar tmp;
- gint count;
-
- ph = pixbuf->pixels;
- sh = pixbuf->pixels + pixbuf->height*pixbuf->rowstride;
- while (ph < sh - pixbuf->rowstride) {
- p = ph;
- s = sh - pixbuf->rowstride;
- for (count = pixbuf->n_channels * pixbuf->width; count > 0; count--, p++, s++) {
- tmp = *p;
- *p = *s;
- *s = tmp;
- }
- sh -= pixbuf->rowstride;
- ph += pixbuf->rowstride;
- }
-}
-
-static gboolean fill_in_context(TGAContext *ctx, GError **err)
-{
- gboolean alpha;
- guint w, h;
-
- g_return_val_if_fail(ctx != NULL, FALSE);
-
- ctx->run_length_encoded =
- ((ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
- || (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
- || (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE));
-
- if (ctx->hdr->has_cmap)
- ctx->cmap_size = ((ctx->hdr->cmap_bpp + 7) >> 3) *
- LE16(ctx->hdr->cmap_n_colors);
-
- alpha = ((ctx->hdr->bpp == 16) ||
- (ctx->hdr->bpp == 32) ||
- (ctx->hdr->has_cmap && (ctx->hdr->cmap_bpp == 32)));
-
- w = LE16(ctx->hdr->width);
- h = LE16(ctx->hdr->height);
-
- if (ctx->sfunc) {
- gint wi = w;
- gint hi = h;
-
- (*ctx->sfunc) (&wi, &hi, ctx->udata);
-
- if (wi == 0 || hi == 0)
- return FALSE;
- }
-
- ctx->pbuf = get_contiguous_pixbuf (w, h, alpha);
-
- if (!ctx->pbuf) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot allocate new pixbuf"));
- return FALSE;
- }
-
- ctx->pbuf_bytes = ctx->pbuf->rowstride * ctx->pbuf->height;
- if ((ctx->hdr->flags & TGA_ORIGIN_UPPER) || ctx->run_length_encoded)
- ctx->pptr = ctx->pbuf->pixels;
- else
- ctx->pptr = ctx->pbuf->pixels + (ctx->pbuf->height - 1)*ctx->pbuf->rowstride;
-
- if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
- ctx->rowstride = ctx->pbuf->width;
- else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
- ctx->rowstride = (alpha ? ctx->pbuf->width * 2 : ctx->pbuf->width);
- else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
- ctx->rowstride = ctx->pbuf->rowstride;
-
- ctx->completed_lines = 0;
- return TRUE;
-}
-
-static void parse_data_for_row_pseudocolor(TGAContext *ctx)
-{
- guchar *s = ctx->in->data;
- guint upper_bound = ctx->pbuf->width;
- guchar *p = ctx->pptr;
-
- for (; upper_bound; upper_bound--, s++) {
- *p++ = ctx->cmap->cols[*s].r;
- *p++ = ctx->cmap->cols[*s].g;
- *p++ = ctx->cmap->cols[*s].b;
- if (ctx->hdr->cmap_bpp == 32)
- *p++ = ctx->cmap->cols[*s].a;
- }
-}
-
-static void swap_channels(TGAContext *ctx)
-{
- guchar swap;
- guint count;
- guchar *p = ctx->pptr;
- for (count = ctx->pbuf->width; count; count--) {
- swap = p[0];
- p[0] = p[2];
- p[2] = swap;
- p += ctx->pbuf->n_channels;
- }
-}
-
-static void parse_data_for_row_truecolor(TGAContext *ctx)
-{
- g_memmove(ctx->pptr, ctx->in->data, ctx->pbuf->rowstride);
- swap_channels(ctx);
-}
-
-static void parse_data_for_row_grayscale(TGAContext *ctx)
-{
- guchar *s = ctx->in->data;
- guint upper_bound = ctx->pbuf->width;
-
- guchar *p = ctx->pptr;
- for (; upper_bound; upper_bound--) {
- p[0] = p[1] = p[2] = *s++;
- if (ctx->pbuf->n_channels == 4)
- p[3] = *s++;
- p += ctx->pbuf->n_channels;
- }
-}
-
-static gboolean parse_data_for_row(TGAContext *ctx, GError **err)
-{
- guint row;
-
- if (ctx->hdr->type == TGA_TYPE_PSEUDOCOLOR)
- parse_data_for_row_pseudocolor(ctx);
- else if (ctx->hdr->type == TGA_TYPE_TRUECOLOR)
- parse_data_for_row_truecolor(ctx);
- else if (ctx->hdr->type == TGA_TYPE_GRAYSCALE)
- parse_data_for_row_grayscale(ctx);
-
- if (ctx->hdr->flags & TGA_ORIGIN_RIGHT)
- pixbuf_flip_row (ctx->pbuf, ctx->pptr);
- if (ctx->hdr->flags & TGA_ORIGIN_UPPER)
- ctx->pptr += ctx->pbuf->rowstride;
- else
- ctx->pptr -= ctx->pbuf->rowstride;
- ctx->pbuf_bytes_done += ctx->pbuf->rowstride;
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
- ctx->done = TRUE;
-
- ctx->in = io_buffer_free_segment(ctx->in, ctx->rowstride, err);
- if (!ctx->in)
- return FALSE;
- row = (ctx->pptr - ctx->pbuf->pixels) / ctx->pbuf->rowstride - 1;
- if (ctx->ufunc)
- (*ctx->ufunc) (ctx->pbuf, 0, row, ctx->pbuf->width, 1, ctx->udata);
- return TRUE;
-}
-
-static void write_rle_data(TGAContext *ctx, TGAColor *color, guint *rle_count)
-{
- for (; *rle_count; (*rle_count)--) {
- g_memmove(ctx->pptr, (guchar *) color, ctx->pbuf->n_channels);
- ctx->pptr += ctx->pbuf->n_channels;
- ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
- return;
- }
-}
-
-static guint parse_rle_data_pseudocolor(TGAContext *ctx)
-{
- guint rle_num, raw_num;
- guchar *s, tag;
- guint n;
-
- g_return_val_if_fail(ctx->in->size > 0, 0);
- s = ctx->in->data;
-
- for (n = 0; n < ctx->in->size; ) {
- tag = *s;
- s++, n++;
- if (tag & 0x80) {
- if (n == ctx->in->size) {
- return --n;
- } else {
- rle_num = (tag & 0x7f) + 1;
- write_rle_data(ctx, &ctx->cmap->cols[*s], &rle_num);
- s++, n++;
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
- ctx->done = TRUE;
- return n;
- }
- }
- } else {
- raw_num = tag + 1;
- if (n + raw_num >= ctx->in->size) {
- return --n;
- } else {
- for (; raw_num; raw_num--) {
- *ctx->pptr++ =
- ctx->cmap->cols[*s].r;
- *ctx->pptr++ =
- ctx->cmap->cols[*s].g;
- *ctx->pptr++ =
- ctx->cmap->cols[*s].b;
- if (ctx->pbuf->n_channels == 4)
- *ctx->pptr++ = ctx->cmap->cols[*s].a;
- s++, n++;
- ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
- ctx->done = TRUE;
- return n;
- }
- }
- }
- }
- }
-
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
- ctx->done = TRUE;
-
- return n;
-}
-
-static guint parse_rle_data_truecolor(TGAContext *ctx)
-{
- TGAColor col;
- guint rle_num, raw_num;
- guchar *s, tag;
- guint n = 0;
-
- g_return_val_if_fail(ctx->in->size > 0, 0);
- s = ctx->in->data;
-
- for (n = 0; n < ctx->in->size; ) {
- tag = *s;
- s++, n++;
- if (tag & 0x80) {
- if (n + ctx->pbuf->n_channels >= ctx->in->size) {
- return --n;
- } else {
- rle_num = (tag & 0x7f) + 1;
- col.b = *s++;
- col.g = *s++;
- col.r = *s++;
- if (ctx->hdr->bpp == 32)
- col.a = *s++;
- n += ctx->pbuf->n_channels;
- write_rle_data(ctx, &col, &rle_num);
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
- ctx->done = TRUE;
- return n;
- }
- }
- } else {
- raw_num = tag + 1;
- if (n + (raw_num * ctx->pbuf->n_channels) >= ctx->in->size) {
- return --n;
- } else {
- for (; raw_num; raw_num--) {
- ctx->pptr[2] = *s++;
- ctx->pptr[1] = *s++;
- ctx->pptr[0] = *s++;
- if (ctx->hdr->bpp == 32)
- ctx->pptr[3] = *s++;
- n += ctx->pbuf->n_channels;
- ctx->pptr += ctx->pbuf->n_channels;
- ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
- ctx->done = TRUE;
- return n;
- }
- }
-
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
- ctx->done = TRUE;
- return n;
- }
- }
- }
- }
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
- ctx->done = TRUE;
- return n;
-}
-
-static guint parse_rle_data_grayscale(TGAContext *ctx)
-{
- TGAColor tone;
- guint rle_num, raw_num;
- guchar *s, tag;
- guint n;
-
- g_return_val_if_fail(ctx->in->size > 0, 0);
- s = ctx->in->data;
-
- for (n = 0; n < ctx->in->size; ) {
- tag = *s;
- s++, n++;
- if (tag & 0x80) {
- if (n + (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
- return --n;
- } else {
- rle_num = (tag & 0x7f) + 1;
- tone.r = tone.g = tone.b = *s;
- s++, n++;
- if (ctx->pbuf->n_channels == 4) {
- tone.a = *s++;
- n++;
- }
- write_rle_data(ctx, &tone, &rle_num);
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
- ctx->done = TRUE;
- return n;
- }
- }
- } else {
- raw_num = tag + 1;
- if (n + raw_num * (ctx->pbuf->n_channels == 4 ? 2 : 1) >= ctx->in->size) {
- return --n;
- } else {
- for (; raw_num; raw_num--) {
- ctx->pptr[0] = ctx->pptr[1] = ctx->pptr[2] = *s;
- s++, n++;
- if (ctx->pbuf->n_channels == 4) {
- ctx->pptr[3] = *s++;
- n++;
- }
- ctx->pptr += ctx->pbuf->n_channels;
- ctx->pbuf_bytes_done += ctx->pbuf->n_channels;
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes) {
- ctx->done = TRUE;
- return n;
- }
- }
- }
- }
- }
- if (ctx->pbuf_bytes_done == ctx->pbuf_bytes)
- ctx->done = TRUE;
- return n;
-}
-
-static gboolean parse_rle_data(TGAContext *ctx, GError **err)
-{
- guint rows = 0;
- guint count = 0;
- guint bytes_done_before = ctx->pbuf_bytes_done;
-
- if (ctx->hdr->type == TGA_TYPE_RLE_PSEUDOCOLOR)
- count = parse_rle_data_pseudocolor(ctx);
- else if (ctx->hdr->type == TGA_TYPE_RLE_TRUECOLOR)
- count = parse_rle_data_truecolor(ctx);
- else if (ctx->hdr->type == TGA_TYPE_RLE_GRAYSCALE)
- count = parse_rle_data_grayscale(ctx);
-
- if (ctx->hdr->flags & TGA_ORIGIN_RIGHT) {
- guchar *row = ctx->pbuf->pixels + (bytes_done_before / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
- guchar *row_after = ctx->pbuf->pixels + (ctx->pbuf_bytes_done / ctx->pbuf->rowstride) * ctx->pbuf->rowstride;
- for (; row < row_after; row += ctx->pbuf->rowstride)
- pixbuf_flip_row (ctx->pbuf, row);
- }
-
- ctx->in = io_buffer_free_segment(ctx->in, count, err);
- if (!ctx->in)
- return FALSE;
-
- if (ctx->done) {
- /* FIXME doing the vertical flipping afterwards is not
- * perfect, but doing it during the rle decoding in place
- * is considerably more work.
- */
- if (!(ctx->hdr->flags & TGA_ORIGIN_UPPER)) {
- pixbuf_flip_vertically (ctx->pbuf);
- ctx->hdr->flags |= TGA_ORIGIN_UPPER;
- }
-
- }
-
- rows = ctx->pbuf_bytes_done / ctx->pbuf->rowstride - bytes_done_before / ctx->pbuf->rowstride;
- if (ctx->ufunc)
- (*ctx->ufunc) (ctx->pbuf, 0, bytes_done_before / ctx->pbuf->rowstride,
- ctx->pbuf->width, rows,
- ctx->udata);
-
- return TRUE;
-}
-
-static gboolean try_colormap(TGAContext *ctx, GError **err)
-{
- static guchar *p;
- static guint n;
-
- g_return_val_if_fail(ctx != NULL, FALSE);
-
- if (ctx->cmap_size == 0) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Image is corrupted or truncated"));
- return FALSE;
- }
-
- ctx->cmap = g_try_malloc(sizeof(TGAColormap));
- if (!ctx->cmap) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot allocate colormap structure"));
- return FALSE;
- }
- ctx->cmap->size = LE16(ctx->hdr->cmap_n_colors);
- ctx->cmap->cols = g_try_malloc(sizeof(TGAColor) * ctx->cmap->size);
- if (!ctx->cmap->cols) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot allocate colormap entries"));
- return FALSE;
- }
-
- p = ctx->in->data;
- for (n = 0; n < ctx->cmap->size; n++) {
- if ((ctx->hdr->cmap_bpp == 15) || (ctx->hdr->cmap_bpp == 16)) {
- guint16 col = p[0] + (p[1] << 8);
- ctx->cmap->cols[n].b = (col >> 7) & 0xf8;
- ctx->cmap->cols[n].g = (col >> 2) & 0xf8;
- ctx->cmap->cols[n].r = col << 3;
- p += 2;
- }
- else if ((ctx->hdr->cmap_bpp == 24) || (ctx->hdr->cmap_bpp == 32)) {
- ctx->cmap->cols[n].b = *p++;
- ctx->cmap->cols[n].g = *p++;
- ctx->cmap->cols[n].r = *p++;
- if (ctx->hdr->cmap_bpp == 32)
- ctx->cmap->cols[n].a = *p++;
- } else {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("Unexpected bitdepth for colormap entries"));
- return FALSE;
- }
- }
- ctx->in = io_buffer_free_segment(ctx->in, ctx->cmap_size, err);
- if (!ctx->in)
- return FALSE;
- return TRUE;
-}
-
-static gboolean try_preload(TGAContext *ctx, GError **err)
-{
- if (!ctx->hdr) {
- if (ctx->in->size >= sizeof(TGAHeader)) {
- ctx->hdr = g_try_malloc(sizeof(TGAHeader));
- if (!ctx->hdr) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot allocate TGA header memory"));
- return FALSE;
- }
- g_memmove(ctx->hdr, ctx->in->data, sizeof(TGAHeader));
- ctx->in = io_buffer_free_segment(ctx->in, sizeof(TGAHeader), err);
-#ifdef DEBUG_TGA
- g_print ("infolen %d "
- "has_cmap %d "
- "type %d "
- "cmap_start %d "
- "cmap_n_colors %d "
- "cmap_bpp %d "
- "x %d y %d width %d height %d bpp %d "
- "flags %#x",
- ctx->hdr->infolen,
- ctx->hdr->has_cmap,
- ctx->hdr->type,
- LE16(ctx->hdr->cmap_start),
- LE16(ctx->hdr->cmap_n_colors),
- ctx->hdr->cmap_bpp,
- LE16(ctx->hdr->x_origin),
- LE16(ctx->hdr->y_origin),
- LE16(ctx->hdr->width),
- LE16(ctx->hdr->height),
- ctx->hdr->bpp,
- ctx->hdr->flags);
-#endif
- if (!ctx->in)
- return FALSE;
- if (LE16(ctx->hdr->width) == 0 ||
- LE16(ctx->hdr->height) == 0) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
- _("TGA image has invalid dimensions"));
- return FALSE;
- }
- if ((ctx->hdr->flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- _("TGA image type not supported"));
- return FALSE;
- }
- switch (ctx->hdr->type) {
- case TGA_TYPE_PSEUDOCOLOR:
- case TGA_TYPE_RLE_PSEUDOCOLOR:
- if (ctx->hdr->bpp != 8) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- _("TGA image type not supported"));
- return FALSE;
- }
- break;
- case TGA_TYPE_TRUECOLOR:
- case TGA_TYPE_RLE_TRUECOLOR:
- if (ctx->hdr->bpp != 24 &&
- ctx->hdr->bpp != 32) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- _("TGA image type not supported"));
- return FALSE;
- }
- break;
- case TGA_TYPE_GRAYSCALE:
- case TGA_TYPE_RLE_GRAYSCALE:
- if (ctx->hdr->bpp != 8 &&
- ctx->hdr->bpp != 16) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- _("TGA image type not supported"));
- return FALSE;
- }
- break;
- default:
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_UNKNOWN_TYPE,
- _("TGA image type not supported"));
- return FALSE;
- }
- if (!fill_in_context(ctx, err))
- return FALSE;
- } else {
- return TRUE;
- }
- }
- if (!ctx->skipped_info) {
- if (ctx->in->size >= ctx->hdr->infolen) {
- ctx->in = io_buffer_free_segment(ctx->in, ctx->hdr->infolen, err);
- if (!ctx->in)
- return FALSE;
- ctx->skipped_info = TRUE;
- } else {
- return TRUE;
- }
- }
- if (ctx->hdr->has_cmap && !ctx->cmap) {
- if (ctx->in->size >= ctx->cmap_size) {
- if (!try_colormap(ctx, err))
- return FALSE;
- } else {
- return TRUE;
- }
- }
- if (!ctx->prepared) {
- if (ctx->pfunc)
- (*ctx->pfunc) (ctx->pbuf, NULL, ctx->udata);
- ctx->prepared = TRUE;
- }
- /* We shouldn't get here anyway. */
- return TRUE;
-}
-
-static gpointer gdk_pixbuf__tga_begin_load(GdkPixbufModuleSizeFunc f0,
- GdkPixbufModulePreparedFunc f1,
- GdkPixbufModuleUpdatedFunc f2,
- gpointer udata, GError **err)
-{
- TGAContext *ctx;
-
- ctx = g_try_malloc(sizeof(TGAContext));
- if (!ctx) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR,
- GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
- _("Cannot allocate memory for TGA context struct"));
- return NULL;
- }
-
- ctx->hdr = NULL;
- ctx->rowstride = 0;
- ctx->run_length_encoded = FALSE;
-
- ctx->cmap = NULL;
- ctx->cmap_size = 0;
-
- ctx->pbuf = NULL;
- ctx->pbuf_bytes = 0;
- ctx->pbuf_bytes_done = 0;
- ctx->pptr = NULL;
-
- ctx->in = io_buffer_new(err);
- if (!ctx->in) {
- g_free(ctx);
- return NULL;
- }
-
- ctx->skipped_info = FALSE;
- ctx->prepared = FALSE;
- ctx->done = FALSE;
-
- ctx->sfunc = f0;
- ctx->pfunc = f1;
- ctx->ufunc = f2;
- ctx->udata = udata;
-
- return ctx;
-}
-
-static gboolean gdk_pixbuf__tga_load_increment(gpointer data,
- const guchar *buffer,
- guint size,
- GError **err)
-{
- TGAContext *ctx = (TGAContext*) data;
- g_return_val_if_fail(ctx != NULL, FALSE);
-
- if (ctx->done)
- return TRUE;
-
- g_return_val_if_fail(buffer != NULL, TRUE);
- ctx->in = io_buffer_append(ctx->in, buffer, size, err);
- if (!ctx->in)
- return FALSE;
- if (!ctx->prepared) {
- if (!try_preload(ctx, err))
- return FALSE;
- if (!ctx->prepared)
- return TRUE;
- if (ctx->in->size == 0)
- return TRUE;
- }
-
- if (ctx->run_length_encoded) {
- if (!parse_rle_data(ctx, err))
- return FALSE;
- } else {
- while (ctx->in->size >= ctx->rowstride) {
- if (ctx->completed_lines >= ctx->pbuf->height) {
- g_set_error_literal(err, GDK_PIXBUF_ERROR, GDK_PIXBUF_ERROR_FAILED,
- _("Excess data in file"));
- return FALSE;
- }
- if (!parse_data_for_row(ctx, err))
- return FALSE;
- ctx->completed_lines++;
- }
- }
-
- return TRUE;
-}
-
-static gboolean gdk_pixbuf__tga_stop_load(gpointer data, GError **err)
-{
- TGAContext *ctx = (TGAContext *) data;
- g_return_val_if_fail(ctx != NULL, FALSE);
-
- if (ctx->hdr &&
- (ctx->hdr->flags & TGA_ORIGIN_UPPER) == 0 &&
- ctx->run_length_encoded &&
- ctx->pbuf) {
- pixbuf_flip_vertically (ctx->pbuf);
- if (ctx->ufunc)
- (*ctx->ufunc) (ctx->pbuf, 0, 0,
- ctx->pbuf->width, ctx->pbuf->height,
- ctx->udata);
- }
- g_free (ctx->hdr);
- if (ctx->cmap) {
- g_free (ctx->cmap->cols);
- g_free (ctx->cmap);
- }
- if (ctx->pbuf)
- g_object_unref (ctx->pbuf);
- if (ctx->in && ctx->in->size)
- ctx->in = io_buffer_free_segment (ctx->in, ctx->in->size, err);
- if (!ctx->in) {
- g_free (ctx);
- return FALSE;
- }
- io_buffer_free (ctx->in);
- g_free (ctx);
- return TRUE;
-}
-
-#ifndef INCLUDE_tga
-#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
-#else
-#define MODULE_ENTRY(function) void _gdk_pixbuf__tga_ ## function
-#endif
-
-MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
-{
- module->begin_load = gdk_pixbuf__tga_begin_load;
- module->stop_load = gdk_pixbuf__tga_stop_load;
- module->load_increment = gdk_pixbuf__tga_load_increment;
-}
-
-MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
-{
- static GdkPixbufModulePattern signature[] = {
- { " \x1\x1", "x ", 100 },
- { " \x1\x9", "x ", 100 },
- { " \x2", "xz ", 99 }, /* only 99 since .CUR also matches this */
- { " \x3", "xz ", 100 },
- { " \xa", "xz ", 100 },
- { " \xb", "xz ", 100 },
- { NULL, NULL, 0 }
- };
- static gchar * mime_types[] = {
- "image/x-tga",
- NULL
- };
- static gchar * extensions[] = {
- "tga",
- "targa",
- NULL
- };
-
- info->name = "tga";
- info->signature = signature;
- info->description = N_("The Targa image format");
- info->mime_types = mime_types;
- info->extensions = extensions;
- info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
- info->license = "LGPL";
-}