diff options
Diffstat (limited to 'gdk-pixbuf/io-tga.c')
-rw-r--r-- | gdk-pixbuf/io-tga.c | 1013 |
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"; -} |