|
Packit |
a4058c |
/* -*- mode: C; c-file-style: "linux" -*- */
|
|
Packit |
a4058c |
/* GdkPixbuf library - QTIF image loader
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* This module extracts image data from QTIF format and uses
|
|
Packit |
a4058c |
* other GDK pixbuf modules to decode the image data.
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* Copyright (C) 2008 Kevin Peng
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* Authors: Kevin Peng <kevin@zycomtech.com>
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* This library is free software; you can redistribute it and/or
|
|
Packit |
a4058c |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
a4058c |
* License as published by the Free Software Foundation; either
|
|
Packit |
a4058c |
* version 2 of the License, or (at your option) any later version.
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
a4058c |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
a4058c |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
a4058c |
* Lesser General Public License for more details.
|
|
Packit |
a4058c |
*
|
|
Packit |
a4058c |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
a4058c |
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
a4058c |
*/
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
#include "config.h"
|
|
Packit |
a4058c |
#include <errno.h>
|
|
Packit |
a4058c |
#include <libintl.h>
|
|
Packit |
a4058c |
#include <stdio.h>
|
|
Packit |
a4058c |
#include <stdlib.h>
|
|
Packit |
a4058c |
#include <string.h>
|
|
Packit |
a4058c |
#include <setjmp.h>
|
|
Packit |
a4058c |
#include "gdk-pixbuf.h"
|
|
Packit |
a4058c |
#include "gdk-pixbuf-private.h"
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/***
|
|
Packit |
a4058c |
* Definitions
|
|
Packit |
a4058c |
*/
|
|
Packit |
a4058c |
/* Read buffer size */
|
|
Packit |
a4058c |
#define READ_BUFFER_SIZE 8192
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Only allow atom of size up to 10MB. */
|
|
Packit |
a4058c |
#define ATOM_SIZE_MAX 100000000
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Aborts after going to through this many atoms. */
|
|
Packit |
a4058c |
#define QTIF_ATOM_COUNT_MAX 10u
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* QTIF static image data tag "idat". */
|
|
Packit |
a4058c |
#define QTIF_TAG_IDATA 0x69646174u
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/***
|
|
Packit |
a4058c |
* Types
|
|
Packit |
a4058c |
*/
|
|
Packit |
a4058c |
/* QTIF State */
|
|
Packit |
a4058c |
typedef enum {
|
|
Packit |
a4058c |
STATE_READY,
|
|
Packit |
a4058c |
STATE_DATA,
|
|
Packit |
a4058c |
STATE_OTHER
|
|
Packit |
a4058c |
} QTIFState;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* QTIF Atom Header */
|
|
Packit |
a4058c |
typedef struct {
|
|
Packit |
a4058c |
guint32 length;
|
|
Packit |
a4058c |
guint32 tag;
|
|
Packit |
a4058c |
} QtHeader;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* QTIF loader context */
|
|
Packit |
a4058c |
typedef struct {
|
|
Packit |
a4058c |
GdkPixbufLoader *loader;
|
|
Packit |
a4058c |
gpointer user_data;
|
|
Packit |
a4058c |
QTIFState state;
|
|
Packit |
a4058c |
guint32 run_length;
|
|
Packit |
a4058c |
gint atom_count;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
guchar header_buffer[sizeof(QtHeader)];
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
GdkPixbufModuleSizeFunc size_func;
|
|
Packit |
a4058c |
GdkPixbufModulePreparedFunc prepare_func;
|
|
Packit |
a4058c |
GdkPixbufModuleUpdatedFunc update_func;
|
|
Packit |
a4058c |
gint cb_prepare_count;
|
|
Packit |
a4058c |
gint cb_update_count;
|
|
Packit |
a4058c |
} QTIFContext;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/***
|
|
Packit |
a4058c |
* Local function prototypes
|
|
Packit |
a4058c |
*/
|
|
Packit |
a4058c |
static GdkPixbuf *gdk_pixbuf__qtif_image_load (FILE *f, GError **error);
|
|
Packit |
a4058c |
static gpointer gdk_pixbuf__qtif_image_begin_load (GdkPixbufModuleSizeFunc size_func,
|
|
Packit |
a4058c |
GdkPixbufModulePreparedFunc prepare_func,
|
|
Packit |
a4058c |
GdkPixbufModuleUpdatedFunc update_func,
|
|
Packit |
a4058c |
gpointer user_data,
|
|
Packit |
a4058c |
GError **error);
|
|
Packit |
a4058c |
static gboolean gdk_pixbuf__qtif_image_stop_load (gpointer context, GError **error);
|
|
Packit |
a4058c |
static gboolean gdk_pixbuf__qtif_image_load_increment(gpointer context,
|
|
Packit |
a4058c |
const guchar *buf, guint size,
|
|
Packit |
a4058c |
GError **error);
|
|
Packit |
a4058c |
static gboolean gdk_pixbuf__qtif_image_create_loader (QTIFContext *context, GError **error);
|
|
Packit |
a4058c |
static gboolean gdk_pixbuf__qtif_image_free_loader (QTIFContext *context, GError **error);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void gdk_pixbuf__qtif_cb_size_prepared(GdkPixbufLoader *loader,
|
|
Packit |
a4058c |
gint width,
|
|
Packit |
a4058c |
gint height,
|
|
Packit |
a4058c |
gpointer user_data);
|
|
Packit |
a4058c |
static void gdk_pixbuf__qtif_cb_area_prepared(GdkPixbufLoader *loader, gpointer user_data);
|
|
Packit |
a4058c |
static void gdk_pixbuf__qtif_cb_area_updated(GdkPixbufLoader *loader,
|
|
Packit |
a4058c |
gint x,
|
|
Packit |
a4058c |
gint y,
|
|
Packit |
a4058c |
gint width,
|
|
Packit |
a4058c |
gint height,
|
|
Packit |
a4058c |
gpointer user_data);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/***
|
|
Packit |
a4058c |
* Function definitions.
|
|
Packit |
a4058c |
*/
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Load QTIF from a file handler. */
|
|
Packit |
a4058c |
static GdkPixbuf *gdk_pixbuf__qtif_image_load (FILE *f, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
guint count;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if(f == NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_BAD_OPTION,
|
|
Packit |
a4058c |
_("Input file descriptor is NULL."));
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
for(count = QTIF_ATOM_COUNT_MAX; count != 0u; count--)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
QtHeader hdr;
|
|
Packit |
a4058c |
size_t rd;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Read QtHeader. */
|
|
Packit |
a4058c |
rd = fread(&hdr, 1, sizeof(QtHeader), f);
|
|
Packit |
a4058c |
if(rd != sizeof(QtHeader))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error_literal(error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
|
Packit |
a4058c |
_("Failed to read QTIF header"));
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
hdr.length = GUINT32_FROM_BE(hdr.length) - sizeof(QtHeader);
|
|
Packit |
a4058c |
if(hdr.length > ATOM_SIZE_MAX)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error(error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
|
Packit |
a4058c |
ngettext ( "QTIF atom size too large (%d byte)",
|
|
Packit |
a4058c |
"QTIF atom size too large (%d bytes)",
|
|
Packit |
a4058c |
hdr.length),
|
|
Packit |
a4058c |
hdr.length);
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
switch(GUINT32_FROM_BE(hdr.tag))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
case QTIF_TAG_IDATA: /* "idat" data atom. */
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
/* Load image using GdkPixbufLoader. */
|
|
Packit |
a4058c |
guchar *buf;
|
|
Packit |
a4058c |
GdkPixbufLoader *loader;
|
|
Packit |
a4058c |
GdkPixbuf *pixbuf = NULL;
|
|
Packit |
a4058c |
GError *tmp = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Allocate read buffer. */
|
|
Packit |
a4058c |
buf = g_try_malloc(READ_BUFFER_SIZE);
|
|
Packit |
a4058c |
if(buf == NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error(error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
|
Packit |
a4058c |
ngettext ( "Failed to allocate %d byte for file read buffer",
|
|
Packit |
a4058c |
"Failed to allocate %d bytes for file read buffer",
|
|
Packit |
a4058c |
READ_BUFFER_SIZE
|
|
Packit |
a4058c |
),
|
|
Packit |
a4058c |
READ_BUFFER_SIZE);
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Create GdkPixbufLoader. */
|
|
Packit |
a4058c |
loader = gdk_pixbuf_loader_new();
|
|
Packit |
a4058c |
if(loader == NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error(error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
|
Packit |
a4058c |
ngettext ( "QTIF atom size too large (%d byte)",
|
|
Packit |
a4058c |
"QTIF atom size too large (%d bytes)",
|
|
Packit |
a4058c |
hdr.length),
|
|
Packit |
a4058c |
hdr.length);
|
|
Packit |
a4058c |
goto clean_up;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Read atom data. */
|
|
Packit |
a4058c |
while(hdr.length != 0u)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if(fread(buf, 1, rd, f) != rd)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error(error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
|
Packit |
a4058c |
_("File error when reading QTIF atom: %s"), g_strerror(errno));
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if(!gdk_pixbuf_loader_write(loader, buf, rd, &tmp))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_propagate_error (error, tmp);
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
hdr.length -= rd;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
clean_up:
|
|
Packit |
a4058c |
/* Release loader */
|
|
Packit |
a4058c |
if(loader != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
gdk_pixbuf_loader_close(loader, NULL);
|
|
Packit |
a4058c |
pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
|
|
Packit |
a4058c |
if(pixbuf != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_object_ref(pixbuf);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
g_object_unref(loader);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
if(buf != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_free(buf);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
return pixbuf;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
default:
|
|
Packit |
a4058c |
/* Skip any other types of atom. */
|
|
Packit |
a4058c |
if(!fseek(f, hdr.length, SEEK_CUR))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error(error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
|
Packit |
a4058c |
ngettext ( "Failed to skip the next %d byte with seek().",
|
|
Packit |
a4058c |
"Failed to skip the next %d bytes with seek().",
|
|
Packit |
a4058c |
hdr.length),
|
|
Packit |
a4058c |
hdr.length);
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Incremental load begin. */
|
|
Packit |
a4058c |
static gpointer gdk_pixbuf__qtif_image_begin_load (GdkPixbufModuleSizeFunc size_func,
|
|
Packit |
a4058c |
GdkPixbufModulePreparedFunc prepare_func,
|
|
Packit |
a4058c |
GdkPixbufModuleUpdatedFunc update_func,
|
|
Packit |
a4058c |
gpointer user_data,
|
|
Packit |
a4058c |
GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
QTIFContext *context;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Create context struct. */
|
|
Packit |
a4058c |
context = g_new0(QTIFContext, 1);
|
|
Packit |
a4058c |
if(context == NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
|
|
Packit |
a4058c |
_("Failed to allocate QTIF context structure."));
|
|
Packit |
a4058c |
return NULL;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Fill context parameters. */
|
|
Packit |
a4058c |
context->loader = NULL;
|
|
Packit |
a4058c |
context->user_data = user_data;
|
|
Packit |
a4058c |
context->state = STATE_READY;
|
|
Packit |
a4058c |
context->run_length = 0u;
|
|
Packit |
a4058c |
context->atom_count = QTIF_ATOM_COUNT_MAX;
|
|
Packit |
a4058c |
context->size_func = size_func;
|
|
Packit |
a4058c |
context->prepare_func = prepare_func;
|
|
Packit |
a4058c |
context->update_func = update_func;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return context;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Incremental load clean up. */
|
|
Packit |
a4058c |
static gboolean gdk_pixbuf__qtif_image_stop_load (gpointer data, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
QTIFContext *context = (QTIFContext *)data;
|
|
Packit |
a4058c |
gboolean ret = TRUE;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if(context->loader != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GError *tmp = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
ret = gdk_pixbuf__qtif_image_free_loader(context, &tmp);
|
|
Packit |
a4058c |
if(!ret)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_propagate_error (error, tmp);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
g_free(context);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return ret;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Create a new GdkPixbufLoader and connect to its signals. */
|
|
Packit |
a4058c |
static gboolean gdk_pixbuf__qtif_image_create_loader (QTIFContext *context, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GError *tmp = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if(context == NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Free existing loader. */
|
|
Packit |
a4058c |
if(context->loader != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
gdk_pixbuf__qtif_image_free_loader(context, &tmp);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Create GdkPixbufLoader object. */
|
|
Packit |
a4058c |
context->loader = gdk_pixbuf_loader_new();
|
|
Packit |
a4058c |
if(context->loader == NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_FAILED,
|
|
Packit |
a4058c |
_("Failed to create GdkPixbufLoader object."));
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Connect signals. */
|
|
Packit |
a4058c |
context->cb_prepare_count = 0;
|
|
Packit |
a4058c |
context->cb_update_count = 0;
|
|
Packit |
a4058c |
if(context->size_func != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_signal_connect(context->loader, "size-prepared",
|
|
Packit |
a4058c |
G_CALLBACK(gdk_pixbuf__qtif_cb_size_prepared),
|
|
Packit |
a4058c |
context);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
if(context->prepare_func != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_signal_connect(context->loader, "area-prepared",
|
|
Packit |
a4058c |
G_CALLBACK(gdk_pixbuf__qtif_cb_area_prepared),
|
|
Packit |
a4058c |
context);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
if(context->update_func != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_signal_connect(context->loader, "area-updated",
|
|
Packit |
a4058c |
G_CALLBACK(gdk_pixbuf__qtif_cb_area_updated),
|
|
Packit |
a4058c |
context);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
return TRUE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Free the GdkPixbufLoader and perform callback if haven't done so. */
|
|
Packit |
a4058c |
static gboolean gdk_pixbuf__qtif_image_free_loader (QTIFContext *context, GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdkPixbuf *pixbuf;
|
|
Packit |
a4058c |
GError *tmp = NULL;
|
|
Packit |
a4058c |
gboolean ret;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if((context == NULL) || (context->loader == NULL))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Close GdkPixbufLoader. */
|
|
Packit |
a4058c |
ret = gdk_pixbuf_loader_close(context->loader, &tmp);
|
|
Packit |
a4058c |
if(!ret)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_propagate_error (error, tmp);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Get GdkPixbuf from GdkPixbufLoader. */
|
|
Packit |
a4058c |
pixbuf = gdk_pixbuf_loader_get_pixbuf(context->loader);
|
|
Packit |
a4058c |
if(pixbuf != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_object_ref(pixbuf);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Free GdkPixbufLoader. */
|
|
Packit |
a4058c |
g_object_ref(context->loader);
|
|
Packit |
a4058c |
context->loader = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if(pixbuf != NULL)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
/* Callback functions should be called for at least once. */
|
|
Packit |
a4058c |
if((context->prepare_func != NULL) && (context->cb_prepare_count == 0))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
(context->prepare_func)(pixbuf, NULL, context->user_data);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
if((context->update_func != NULL) && (context->cb_update_count == 0))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
gint width;
|
|
Packit |
a4058c |
gint height;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
width = gdk_pixbuf_get_width(pixbuf);
|
|
Packit |
a4058c |
height = gdk_pixbuf_get_height(pixbuf);
|
|
Packit |
a4058c |
(context->update_func)(pixbuf, 0, 0, width, height, context->user_data);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Free GdkPixbuf (callback function should ref it). */
|
|
Packit |
a4058c |
g_object_ref(pixbuf);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return ret;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Incrementally load the next chunk of data. */
|
|
Packit |
a4058c |
static gboolean gdk_pixbuf__qtif_image_load_increment (gpointer data,
|
|
Packit |
a4058c |
const guchar *buf, guint size,
|
|
Packit |
a4058c |
GError **error)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
QTIFContext *context = (QTIFContext *)data;
|
|
Packit |
a4058c |
GError *tmp = NULL;
|
|
Packit |
a4058c |
gboolean ret = TRUE; /* Return TRUE for insufficient data. */
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
while(ret && (size != 0u))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
switch(context->state)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
case STATE_READY:
|
|
Packit |
a4058c |
/* Abort if we have seen too many atoms. */
|
|
Packit |
a4058c |
if(context->atom_count == 0u)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error_literal (error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
|
Packit |
a4058c |
_("Failed to find an image data atom."));
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
context->atom_count--;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Copy to header buffer in context, in case supplied data is not enough. */
|
|
Packit |
a4058c |
while (context->run_length < sizeof(QtHeader) && size > 0u)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
context->header_buffer[context->run_length] = *buf;
|
|
Packit |
a4058c |
context->run_length++;
|
|
Packit |
a4058c |
buf++;
|
|
Packit |
a4058c |
size--;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Parse buffer as QT header. */
|
|
Packit |
a4058c |
if(context->run_length == sizeof(QtHeader))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
QtHeader *hdr = (QtHeader *)context->header_buffer;
|
|
Packit |
a4058c |
context->run_length = GUINT32_FROM_BE(hdr->length) - sizeof(QtHeader);
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Atom max size check. */
|
|
Packit |
a4058c |
if(context->run_length > ATOM_SIZE_MAX)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_set_error(error, GDK_PIXBUF_ERROR,
|
|
Packit |
a4058c |
GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
|
|
Packit |
a4058c |
ngettext ( "QTIF atom size too large (%d byte)",
|
|
Packit |
a4058c |
"QTIF atom size too large (%d bytes)",
|
|
Packit |
a4058c |
hdr->length),
|
|
Packit |
a4058c |
hdr->length);
|
|
Packit |
a4058c |
return FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Set state according to atom type. */
|
|
Packit |
a4058c |
if(GUINT32_FROM_BE(hdr->tag) == QTIF_TAG_IDATA)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GError *tmp = NULL;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
context->state = STATE_DATA;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Create GdkPixbufLoader for this image data. */
|
|
Packit |
a4058c |
ret = gdk_pixbuf__qtif_image_create_loader(context, &tmp);
|
|
Packit |
a4058c |
if(!ret)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_propagate_error (error, tmp);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
else
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
context->state = STATE_OTHER;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
default: /* Both STATE_DATA and STATE_OTHER will come here. */
|
|
Packit |
a4058c |
/* Check for atom boundary. */
|
|
Packit |
a4058c |
if(context->run_length > size)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
/* Supply image data to GdkPixbufLoader if in STATE_DATA. */
|
|
Packit |
a4058c |
if(context->state == STATE_DATA)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
tmp = NULL;
|
|
Packit |
a4058c |
ret = gdk_pixbuf_loader_write(context->loader, buf, size, &tmp);
|
|
Packit |
a4058c |
if(!ret && (error != NULL) && (*error == NULL))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_propagate_error (error, tmp);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
context->run_length -= size;
|
|
Packit |
a4058c |
size = 0u;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
else
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
/* Supply image data to GdkPixbufLoader if in STATE_DATA. */
|
|
Packit |
a4058c |
if(context->state == STATE_DATA)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
gboolean r;
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Here we should have concluded a complete image atom. */
|
|
Packit |
a4058c |
tmp = NULL;
|
|
Packit |
a4058c |
ret = gdk_pixbuf_loader_write(context->loader, buf, context->run_length, &tmp);
|
|
Packit |
a4058c |
if(!ret && (error != NULL) && (*error == NULL))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_propagate_error (error, tmp);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Free GdkPixbufLoader and handle callback. */
|
|
Packit |
a4058c |
tmp = NULL;
|
|
Packit |
a4058c |
r = gdk_pixbuf__qtif_image_free_loader(context, &tmp);
|
|
Packit |
a4058c |
if(!r)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
if((error != NULL) && (*error == NULL))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
g_propagate_error (error, tmp);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
ret = FALSE;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
buf = &buf[context->run_length];
|
|
Packit |
a4058c |
size -= context->run_length;
|
|
Packit |
a4058c |
context->run_length = 0u;
|
|
Packit |
a4058c |
context->state = STATE_READY;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
break;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
return ret;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
/* Event handlers */
|
|
Packit |
a4058c |
static void gdk_pixbuf__qtif_cb_size_prepared(GdkPixbufLoader *loader,
|
|
Packit |
a4058c |
gint width,
|
|
Packit |
a4058c |
gint height,
|
|
Packit |
a4058c |
gpointer user_data)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
QTIFContext *context = (QTIFContext *)user_data;
|
|
Packit |
a4058c |
if((context != NULL) && (context->size_func != NULL))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
(context->size_func)(&width, &height, context->user_data);
|
|
Packit |
a4058c |
context->cb_prepare_count++;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void gdk_pixbuf__qtif_cb_area_prepared(GdkPixbufLoader *loader, gpointer user_data)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
QTIFContext *context = (QTIFContext *)user_data;
|
|
Packit |
a4058c |
if((loader != NULL) && (context != NULL) && (context->prepare_func != NULL))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(context->loader);
|
|
Packit |
a4058c |
(context->prepare_func)(pixbuf, NULL, context->user_data);
|
|
Packit |
a4058c |
context->cb_update_count++;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
static void gdk_pixbuf__qtif_cb_area_updated(GdkPixbufLoader *loader,
|
|
Packit |
a4058c |
gint x,
|
|
Packit |
a4058c |
gint y,
|
|
Packit |
a4058c |
gint width,
|
|
Packit |
a4058c |
gint height,
|
|
Packit |
a4058c |
gpointer user_data)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
QTIFContext *context = (QTIFContext *)user_data;
|
|
Packit |
a4058c |
if((loader != NULL) && (context != NULL) && (context->update_func != NULL))
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
GdkPixbuf *pixbuf = gdk_pixbuf_loader_get_pixbuf(context->loader);
|
|
Packit |
a4058c |
(context->update_func)(pixbuf, x, y, width, height, context->user_data);
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
#ifndef INCLUDE_qtif
|
|
Packit |
a4058c |
#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
|
|
Packit |
a4058c |
#else
|
|
Packit |
a4058c |
#define MODULE_ENTRY(function) void _gdk_pixbuf__qtif_ ## function
|
|
Packit |
a4058c |
#endif
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
module->load = gdk_pixbuf__qtif_image_load;
|
|
Packit |
a4058c |
module->begin_load = gdk_pixbuf__qtif_image_begin_load;
|
|
Packit |
a4058c |
module->stop_load = gdk_pixbuf__qtif_image_stop_load;
|
|
Packit |
a4058c |
module->load_increment = gdk_pixbuf__qtif_image_load_increment;
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
|
|
Packit |
a4058c |
{
|
|
Packit |
a4058c |
static const GdkPixbufModulePattern signature[] = {
|
|
Packit |
a4058c |
{ "abcdidsc", "xxxx ", 100 },
|
|
Packit |
a4058c |
{ "abcdidat", "xxxx ", 100 },
|
|
Packit |
a4058c |
{ NULL, NULL, 0 }
|
|
Packit |
a4058c |
};
|
|
Packit |
a4058c |
static const gchar *mime_types[] = {
|
|
Packit |
a4058c |
"image/x-quicktime",
|
|
Packit |
a4058c |
"image/qtif",
|
|
Packit |
a4058c |
NULL
|
|
Packit |
a4058c |
};
|
|
Packit |
a4058c |
static const gchar *extensions[] = {
|
|
Packit |
a4058c |
"qtif",
|
|
Packit |
a4058c |
"qif",
|
|
Packit |
a4058c |
NULL
|
|
Packit |
a4058c |
};
|
|
Packit |
a4058c |
|
|
Packit |
a4058c |
info->name = "qtif";
|
|
Packit |
a4058c |
info->signature = (GdkPixbufModulePattern *) signature;
|
|
Packit |
a4058c |
info->description = NC_("image format", "QuickTime");
|
|
Packit |
a4058c |
info->mime_types = (gchar **) mime_types;
|
|
Packit |
a4058c |
info->extensions = (gchar **) extensions;
|
|
Packit |
a4058c |
info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
|
|
Packit |
a4058c |
info->license = "LGPL";
|
|
Packit |
a4058c |
}
|
|
Packit |
a4058c |
|