Blame src/gd_gd2.c

Packit Service df60bb
/*
Packit Service df60bb
   * gd_gd2.c
Packit Service df60bb
   *
Packit Service df60bb
   * Implements the I/O and support for the GD2 format.
Packit Service df60bb
   *
Packit Service df60bb
   * Changing the definition of GD2_DBG (below) will cause copious messages
Packit Service df60bb
   * to be displayed while it processes requests.
Packit Service df60bb
   *
Packit Service df60bb
   * Designed, Written & Copyright 1999, Philip Warner.
Packit Service df60bb
   *
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
/**
Packit Service df60bb
 * File: GD2 IO
Packit Service df60bb
 *
Packit Service df60bb
 * Read and write GD2 images.
Packit Service df60bb
 *
Packit Service df60bb
 * The GD2 image format is a proprietary image format of libgd. *It has to be*
Packit Service df60bb
 * *regarded as being obsolete, and should only be used for development and*
Packit Service df60bb
 * *testing purposes.*
Packit Service df60bb
 *
Packit Service df60bb
 * Structure of a GD2 image file:
Packit Service df60bb
 *  - file header
Packit Service df60bb
 *  - chunk headers (only for compressed data)
Packit Service df60bb
 *  - color header (either truecolor or palette)
Packit Service df60bb
 *  - chunks of image data (chunk-row-major, top to bottom, left to right)
Packit Service df60bb
 *
Packit Service df60bb
 * All numbers are stored in big-endian format.
Packit Service df60bb
 *
Packit Service df60bb
 * File header structure:
Packit Service df60bb
 *  signature     - 4 bytes (always "gd2\0")
Packit Service df60bb
 *  version       - 1 word (e.g. "\0\002")
Packit Service df60bb
 *  width         - 1 word
Packit Service df60bb
 *  height        - 1 word
Packit Service df60bb
 *  chunk_size    - 1 word
Packit Service df60bb
 *  format        - 1 word
Packit Service df60bb
 *  x_chunk_count - 1 word
Packit Service df60bb
 *  y_chunk_count - 1 word
Packit Service df60bb
 *
Packit Service df60bb
 * Recognized formats:
Packit Service df60bb
 *  1 - raw palette image data
Packit Service df60bb
 *  2 - compressed palette image data
Packit Service df60bb
 *  3 - raw truecolor image data
Packit Service df60bb
 *  4 - compressed truecolor image data
Packit Service df60bb
 *
Packit Service df60bb
 * Chunk header:
Packit Service df60bb
 *  offset - 1 dword
Packit Service df60bb
 *  size   - 1 dword
Packit Service df60bb
 *
Packit Service df60bb
 * There are x_chunk_count * y_chunk_count chunk headers. 
Packit Service df60bb
 *
Packit Service df60bb
 * Truecolor image color header:
Packit Service df60bb
 *  truecolor   - 1 byte (always "\001")
Packit Service df60bb
 *  transparent - 1 dword (ARGB color)
Packit Service df60bb
 *
Packit Service df60bb
 * Palette image color header:
Packit Service df60bb
 *  truecolor   - 1 byte (always "\0")
Packit Service df60bb
 *  count       - 1 word (the number of used palette colors)
Packit Service df60bb
 *  transparent - 1 dword (ARGB color)
Packit Service df60bb
 *  palette     - 256 dwords (RGBA colors)
Packit Service df60bb
 *
Packit Service df60bb
 * Chunk structure:
Packit Service df60bb
 *  Sequential pixel data of a rectangular area (chunk_size x chunk_size),
Packit Service df60bb
 *  row-major from top to bottom, left to right:
Packit Service df60bb
 *  - 1 byte per pixel for palette images
Packit Service df60bb
 *  - 1 dword (ARGB) per pixel for truecolor images
Packit Service df60bb
 *
Packit Service df60bb
 *  Depending on format, the chunk may be ZLIB compressed.
Packit Service df60bb
 */
Packit Service df60bb
Packit Service df60bb
#ifdef HAVE_CONFIG_H
Packit Service df60bb
#include "config.h"
Packit Service df60bb
#endif
Packit Service df60bb
Packit Service df60bb
/* 2.0.29: no more errno.h, makes windows happy */
Packit Service df60bb
#include <math.h>
Packit Service df60bb
#include <limits.h>
Packit Service df60bb
#include <string.h>
Packit Service df60bb
#include "gd.h"
Packit Service df60bb
#include "gd_errors.h"
Packit Service df60bb
#include "gdhelpers.h"
Packit Service df60bb
Packit Service df60bb
/* 2.03: gd2 is no longer mandatory */
Packit Service df60bb
/* JCE - test after including gd.h so that HAVE_LIBZ can be set in
Packit Service df60bb
 * a config.h file included by gd.h */
Packit Service df60bb
#ifdef HAVE_LIBZ
Packit Service df60bb
#include <zlib.h>
Packit Service df60bb
Packit Service df60bb
#define TRUE 1
Packit Service df60bb
#define FALSE 0
Packit Service df60bb
Packit Service df60bb
/* 2.11: not part of the API, as the save routine can figure it out
Packit Service df60bb
	from im->trueColor, and the load routine doesn't need to tell
Packit Service df60bb
	the end user the saved format. NOTE: adding 2 is assumed
Packit Service df60bb
	to result in the correct format value for truecolor! */
Packit Service df60bb
#define GD2_FMT_TRUECOLOR_RAW 3
Packit Service df60bb
#define GD2_FMT_TRUECOLOR_COMPRESSED 4
Packit Service df60bb
Packit Service df60bb
#define gd2_compressed(fmt) (((fmt) == GD2_FMT_COMPRESSED) || \
Packit Service df60bb
	((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
Packit Service df60bb
Packit Service df60bb
#define gd2_truecolor(fmt) (((fmt) == GD2_FMT_TRUECOLOR_RAW) || \
Packit Service df60bb
	((fmt) == GD2_FMT_TRUECOLOR_COMPRESSED))
Packit Service df60bb
Packit Service df60bb
/* Use this for commenting out debug-print statements. */
Packit Service df60bb
/* Just use the first '#define' to allow all the prints... */
Packit Service df60bb
/*#define GD2_DBG(s) (s) */
Packit Service df60bb
#define GD2_DBG(s)
Packit Service df60bb
Packit Service df60bb
typedef struct {
Packit Service df60bb
	int offset;
Packit Service df60bb
	int size;
Packit Service df60bb
}
Packit Service df60bb
t_chunk_info;
Packit Service df60bb
Packit Service df60bb
extern int _gdGetColors (gdIOCtx * in, gdImagePtr im, int gd2xFlag);
Packit Service df60bb
extern void _gdPutColors (gdImagePtr im, gdIOCtx * out);
Packit Service df60bb
Packit Service df60bb
/* */
Packit Service df60bb
/* Read the extra info in the gd2 header. */
Packit Service df60bb
/* */
Packit Service df60bb
static int
Packit Service df60bb
_gd2GetHeader (gdIOCtxPtr in, int *sx, int *sy,
Packit Service df60bb
               int *cs, int *vers, int *fmt, int *ncx, int *ncy,
Packit Service df60bb
               t_chunk_info ** chunkIdx)
Packit Service df60bb
{
Packit Service df60bb
	int i;
Packit Service df60bb
	int ch;
Packit Service df60bb
	char id[5];
Packit Service df60bb
	t_chunk_info *cidx;
Packit Service df60bb
	int sidx;
Packit Service df60bb
	int nc;
Packit Service df60bb
Packit Service df60bb
	GD2_DBG (printf ("Reading gd2 header info\n"));
Packit Service df60bb
Packit Service df60bb
	for (i = 0; i < 4; i++) {
Packit Service df60bb
		ch = gdGetC (in);
Packit Service df60bb
		if (ch == EOF) {
Packit Service df60bb
			goto fail1;
Packit Service df60bb
		};
Packit Service df60bb
		id[i] = ch;
Packit Service df60bb
	};
Packit Service df60bb
	id[4] = 0;
Packit Service df60bb
Packit Service df60bb
	GD2_DBG (printf ("Got file code: %s\n", id));
Packit Service df60bb
Packit Service df60bb
	/* Equiv. of 'magick'.  */
Packit Service df60bb
	if (strcmp (id, GD2_ID) != 0) {
Packit Service df60bb
		GD2_DBG (printf ("Not a valid gd2 file\n"));
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/* Version */
Packit Service df60bb
	if (gdGetWord (vers, in) != 1) {
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
	GD2_DBG (printf ("Version: %d\n", *vers));
Packit Service df60bb
Packit Service df60bb
	if ((*vers != 1) && (*vers != 2)) {
Packit Service df60bb
		GD2_DBG (printf ("Bad version: %d\n", *vers));
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/* Image Size */
Packit Service df60bb
	if (!gdGetWord (sx, in)) {
Packit Service df60bb
		GD2_DBG (printf ("Could not get x-size\n"));
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	}
Packit Service df60bb
	if (!gdGetWord (sy, in)) {
Packit Service df60bb
		GD2_DBG (printf ("Could not get y-size\n"));
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	}
Packit Service df60bb
	GD2_DBG (printf ("Image is %dx%d\n", *sx, *sy));
Packit Service df60bb
Packit Service df60bb
	/* Chunk Size (pixels, not bytes!) */
Packit Service df60bb
	if (gdGetWord (cs, in) != 1) {
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
	GD2_DBG (printf ("ChunkSize: %d\n", *cs));
Packit Service df60bb
Packit Service df60bb
	if ((*cs < GD2_CHUNKSIZE_MIN) || (*cs > GD2_CHUNKSIZE_MAX)) {
Packit Service df60bb
		GD2_DBG (printf ("Bad chunk size: %d\n", *cs));
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/* Data Format */
Packit Service df60bb
	if (gdGetWord (fmt, in) != 1) {
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
	GD2_DBG (printf ("Format: %d\n", *fmt));
Packit Service df60bb
Packit Service df60bb
	if ((*fmt != GD2_FMT_RAW) && (*fmt != GD2_FMT_COMPRESSED) &&
Packit Service df60bb
	        (*fmt != GD2_FMT_TRUECOLOR_RAW) &&
Packit Service df60bb
	        (*fmt != GD2_FMT_TRUECOLOR_COMPRESSED)) {
Packit Service df60bb
		GD2_DBG (printf ("Bad data format: %d\n", *fmt));
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
	/* # of chunks wide */
Packit Service df60bb
	if (gdGetWord (ncx, in) != 1) {
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
	GD2_DBG (printf ("%d Chunks Wide\n", *ncx));
Packit Service df60bb
Packit Service df60bb
	/* # of chunks high */
Packit Service df60bb
	if (gdGetWord (ncy, in) != 1) {
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
	GD2_DBG (printf ("%d Chunks vertically\n", *ncy));
Packit Service df60bb
Packit Service df60bb
	if (gd2_compressed (*fmt)) {
Packit Service df60bb
		if (*ncx <= 0 || *ncy <= 0 || *ncx > INT_MAX / *ncy) {
Packit Service df60bb
			GD2_DBG(printf ("Illegal chunk counts: %d * %d\n", *ncx, *ncy));
Packit Service df60bb
			goto fail1;
Packit Service df60bb
		}
Packit Service df60bb
		nc = (*ncx) * (*ncy);
Packit Service df60bb
Packit Service df60bb
		GD2_DBG (printf ("Reading %d chunk index entries\n", nc));
Packit Service df60bb
		if (overflow2(sizeof(t_chunk_info), nc)) {
Packit Service df60bb
			goto fail1;
Packit Service df60bb
		}
Packit Service df60bb
		sidx = sizeof (t_chunk_info) * nc;
Packit Service df60bb
		if (sidx <= 0) {
Packit Service df60bb
			goto fail1;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		cidx = gdCalloc (sidx, 1);
Packit Service df60bb
		if (cidx == NULL) {
Packit Service df60bb
			goto fail1;
Packit Service df60bb
		}
Packit Service df60bb
		for (i = 0; i < nc; i++) {
Packit Service df60bb
			if (gdGetInt (&cidx[i].offset, in) != 1) {
Packit Service df60bb
				goto fail2;
Packit Service df60bb
			};
Packit Service df60bb
			if (gdGetInt (&cidx[i].size, in) != 1) {
Packit Service df60bb
				goto fail2;
Packit Service df60bb
			};
Packit Service df60bb
			if (cidx[i].offset < 0 || cidx[i].size < 0)
Packit Service df60bb
				goto fail2;
Packit Service df60bb
		};
Packit Service df60bb
		*chunkIdx = cidx;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	GD2_DBG (printf ("gd2 header complete\n"));
Packit Service df60bb
Packit Service df60bb
	return 1;
Packit Service df60bb
fail2:
Packit Service df60bb
	gdFree(cidx);
Packit Service df60bb
fail1:
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static gdImagePtr
Packit Service df60bb
_gd2CreateFromFile (gdIOCtxPtr in, int *sx, int *sy,
Packit Service df60bb
                    int *cs, int *vers, int *fmt,
Packit Service df60bb
                    int *ncx, int *ncy, t_chunk_info ** cidx)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
Packit Service df60bb
	if (_gd2GetHeader (in, sx, sy, cs, vers, fmt, ncx, ncy, cidx) != 1) {
Packit Service df60bb
		GD2_DBG (printf ("Bad GD2 header\n"));
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	}
Packit Service df60bb
	if (gd2_truecolor (*fmt)) {
Packit Service df60bb
		im = gdImageCreateTrueColor (*sx, *sy);
Packit Service df60bb
	} else {
Packit Service df60bb
		im = gdImageCreate (*sx, *sy);
Packit Service df60bb
	}
Packit Service df60bb
	if (im == NULL) {
Packit Service df60bb
		GD2_DBG (printf ("Could not create gdImage\n"));
Packit Service df60bb
		goto fail2;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	if (!_gdGetColors (in, im, (*vers) == 2)) {
Packit Service df60bb
		GD2_DBG (printf ("Could not read color palette\n"));
Packit Service df60bb
		goto fail3;
Packit Service df60bb
	}
Packit Service df60bb
	GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
Packit Service df60bb
Packit Service df60bb
	return im;
Packit Service df60bb
Packit Service df60bb
fail3:
Packit Service df60bb
	gdImageDestroy (im);
Packit Service df60bb
fail2:
Packit Service df60bb
	gdFree(*cidx);
Packit Service df60bb
fail1:
Packit Service df60bb
	return 0;
Packit Service df60bb
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static int
Packit Service df60bb
_gd2ReadChunk (int offset, char *compBuf, int compSize, char *chunkBuf,
Packit Service df60bb
               uLongf * chunkLen, gdIOCtx * in)
Packit Service df60bb
{
Packit Service df60bb
	int zerr;
Packit Service df60bb
Packit Service df60bb
	if (gdTell (in) != offset) {
Packit Service df60bb
		GD2_DBG (printf ("Positioning in file to %d\n", offset));
Packit Service df60bb
		gdSeek (in, offset);
Packit Service df60bb
	} else {
Packit Service df60bb
		GD2_DBG (printf ("Already Positioned in file to %d\n", offset));
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/* Read and uncompress an entire chunk. */
Packit Service df60bb
	GD2_DBG (printf ("Reading file\n"));
Packit Service df60bb
	if (gdGetBuf (compBuf, compSize, in) != compSize) {
Packit Service df60bb
		return FALSE;
Packit Service df60bb
	};
Packit Service df60bb
	GD2_DBG (printf
Packit Service df60bb
	         ("Got %d bytes. Uncompressing into buffer of %d bytes\n", compSize,
Packit Service df60bb
	          *chunkLen));
Packit Service df60bb
	zerr =
Packit Service df60bb
	    uncompress ((unsigned char *) chunkBuf, chunkLen,
Packit Service df60bb
	                (unsigned char *) compBuf, compSize);
Packit Service df60bb
	if (zerr != Z_OK) {
Packit Service df60bb
		GD2_DBG (printf ("Error %d from uncompress\n", zerr));
Packit Service df60bb
		return FALSE;
Packit Service df60bb
	};
Packit Service df60bb
	GD2_DBG (printf ("Got chunk\n"));
Packit Service df60bb
	return TRUE;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromGd2
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromGd2> is called to load images from gd2 format
Packit Service df60bb
    files. Invoke <gdImageCreateFromGd2> with an already opened
Packit Service df60bb
    pointer to a file containing the desired image in the gd2 file
Packit Service df60bb
    format, which is specific to gd2 and intended for fast loading of
Packit Service df60bb
    parts of large images. (It is a compressed format, but generally
Packit Service df60bb
    not as good as maximum compression of the entire image would be.)
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromGd2> returns a <gdImagePtr> to the new image, or
Packit Service df60bb
    NULL if unable to load the image (most often because the file is
Packit Service df60bb
    corrupt or does not contain a gd format
Packit Service df60bb
    image). <gdImageCreateFromGd2> does not close the file. You can
Packit Service df60bb
    inspect the sx and sy members of the image to determine its
Packit Service df60bb
    size. The image must eventually be destroyed using
Packit Service df60bb
    <gdImageDestroy>.
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
  Variants:
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromGd2Ptr> creates an image from GD data (i.e. the
Packit Service df60bb
    contents of a GD2 file) already in memory.
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromGd2Ctx> reads in an image using the functions in
Packit Service df60bb
    a <gdIOCtx> struct.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    infile - The input FILE pointer
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    A pointer to the new image or NULL if an error occurred.
Packit Service df60bb
Packit Service df60bb
  Example:
Packit Service df60bb
Packit Service df60bb
    > gdImagePtr im;
Packit Service df60bb
    > FILE *in;
Packit Service df60bb
    > in = fopen("mygd.gd2", "rb");
Packit Service df60bb
    > im = gdImageCreateFromGd2(in);
Packit Service df60bb
    > fclose(in);
Packit Service df60bb
    > // ... Use the image ...
Packit Service df60bb
    > gdImageDestroy(im);
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2 (FILE * inFile)
Packit Service df60bb
{
Packit Service df60bb
	gdIOCtx *in = gdNewFileCtx (inFile);
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
Packit Service df60bb
	if (in == NULL) return NULL;
Packit Service df60bb
	im = gdImageCreateFromGd2Ctx (in);
Packit Service df60bb
Packit Service df60bb
	in->gd_free (in);
Packit Service df60bb
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromGd2Ptr
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    size - size of GD2 data in bytes.
Packit Service df60bb
    data - GD2 data (i.e. contents of a GIF file).
Packit Service df60bb
Packit Service df60bb
  See <gdImageCreateFromGd2>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ptr (int size, void *data)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
Packit Service df60bb
	if(!in)
Packit Service df60bb
		return 0;
Packit Service df60bb
	im = gdImageCreateFromGd2Ctx (in);
Packit Service df60bb
	in->gd_free (in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromGd2Ctx
Packit Service df60bb
Packit Service df60bb
  Reads in a GD2 image via a <gdIOCtx> struct.  See
Packit Service df60bb
  <gdImageCreateFromGd2>.  
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
Packit Service df60bb
{
Packit Service df60bb
	int sx, sy;
Packit Service df60bb
	int i;
Packit Service df60bb
	int ncx, ncy, nc, cs, cx, cy;
Packit Service df60bb
	int x, y, ylo, yhi, xlo, xhi;
Packit Service df60bb
	int vers, fmt;
Packit Service df60bb
	t_chunk_info *chunkIdx = NULL;	/* So we can gdFree it with impunity. */
Packit Service df60bb
	unsigned char *chunkBuf = NULL;	/* So we can gdFree it with impunity. */
Packit Service df60bb
	int chunkNum = 0;
Packit Service df60bb
	int chunkMax = 0;
Packit Service df60bb
	uLongf chunkLen;
Packit Service df60bb
	int chunkPos = 0;
Packit Service df60bb
	int compMax = 0;
Packit Service df60bb
	int bytesPerPixel;
Packit Service df60bb
	char *compBuf = NULL;		/* So we can gdFree it with impunity. */
Packit Service df60bb
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
Packit Service df60bb
	/* Get the header */
Packit Service df60bb
	im =
Packit Service df60bb
	    _gd2CreateFromFile (in, &sx, &sy, &cs, &vers, &fmt, &ncx, &ncy,
Packit Service df60bb
	                        &chunkIdx);
Packit Service df60bb
	if (im == NULL) {
Packit Service df60bb
		/* No need to free chunkIdx as _gd2CreateFromFile does it for us. */
Packit Service df60bb
		return 0;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	bytesPerPixel = im->trueColor ? 4 : 1;
Packit Service df60bb
	nc = ncx * ncy;
Packit Service df60bb
Packit Service df60bb
	if (gd2_compressed (fmt)) {
Packit Service df60bb
		/* Find the maximum compressed chunk size. */
Packit Service df60bb
		compMax = 0;
Packit Service df60bb
		for (i = 0; (i < nc); i++) {
Packit Service df60bb
			if (chunkIdx[i].size > compMax) {
Packit Service df60bb
				compMax = chunkIdx[i].size;
Packit Service df60bb
			};
Packit Service df60bb
		};
Packit Service df60bb
		compMax++;
Packit Service df60bb
Packit Service df60bb
		/* Allocate buffers */
Packit Service df60bb
		chunkMax = cs * bytesPerPixel * cs;
Packit Service df60bb
		chunkBuf = gdCalloc (chunkMax, 1);
Packit Service df60bb
		if (!chunkBuf) {
Packit Service df60bb
			goto fail;
Packit Service df60bb
		}
Packit Service df60bb
		compBuf = gdCalloc (compMax, 1);
Packit Service df60bb
		if (!compBuf) {
Packit Service df60bb
			goto fail;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		GD2_DBG (printf ("Largest compressed chunk is %d bytes\n", compMax));
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/*      if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
Packit Service df60bb
	/*              goto fail2; */
Packit Service df60bb
	/*      }; */
Packit Service df60bb
Packit Service df60bb
	/* Read the data... */
Packit Service df60bb
	for (cy = 0; (cy < ncy); cy++) {
Packit Service df60bb
		for (cx = 0; (cx < ncx); cx++) {
Packit Service df60bb
Packit Service df60bb
			ylo = cy * cs;
Packit Service df60bb
			yhi = ylo + cs;
Packit Service df60bb
			if (yhi > im->sy) {
Packit Service df60bb
				yhi = im->sy;
Packit Service df60bb
			};
Packit Service df60bb
Packit Service df60bb
			GD2_DBG (printf
Packit Service df60bb
			         ("Processing Chunk %d (%d, %d), y from %d to %d\n",
Packit Service df60bb
			          chunkNum, cx, cy, ylo, yhi));
Packit Service df60bb
Packit Service df60bb
			if (gd2_compressed (fmt)) {
Packit Service df60bb
Packit Service df60bb
				chunkLen = chunkMax;
Packit Service df60bb
Packit Service df60bb
				if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
Packit Service df60bb
				                    compBuf,
Packit Service df60bb
				                    chunkIdx[chunkNum].size,
Packit Service df60bb
				                    (char *) chunkBuf, &chunkLen, in)) {
Packit Service df60bb
					GD2_DBG (printf ("Error reading comproessed chunk\n"));
Packit Service df60bb
					goto fail;
Packit Service df60bb
				};
Packit Service df60bb
Packit Service df60bb
				chunkPos = 0;
Packit Service df60bb
			};
Packit Service df60bb
Packit Service df60bb
			for (y = ylo; (y < yhi); y++) {
Packit Service df60bb
Packit Service df60bb
				xlo = cx * cs;
Packit Service df60bb
				xhi = xlo + cs;
Packit Service df60bb
				if (xhi > im->sx) {
Packit Service df60bb
					xhi = im->sx;
Packit Service df60bb
				};
Packit Service df60bb
				/*GD2_DBG(printf("y=%d: ",y)); */
Packit Service df60bb
				if (!gd2_compressed (fmt)) {
Packit Service df60bb
					for (x = xlo; x < xhi; x++) {
Packit Service df60bb
Packit Service df60bb
						if (im->trueColor) {
Packit Service df60bb
							if (!gdGetInt (&im->tpixels[y][x], in)) {
Packit Service df60bb
								gd_error("gd2: EOF while reading\n");
Packit Service df60bb
								goto fail;
Packit Service df60bb
							}
Packit Service df60bb
						} else {
Packit Service df60bb
							int ch;
Packit Service df60bb
							if (!gdGetByte (&ch, in)) {
Packit Service df60bb
								gd_error("gd2: EOF while reading\n");
Packit Service df60bb
								goto fail;
Packit Service df60bb
							}
Packit Service df60bb
							im->pixels[y][x] = ch;
Packit Service df60bb
						}
Packit Service df60bb
					}
Packit Service df60bb
				} else {
Packit Service df60bb
					for (x = xlo; x < xhi; x++) {
Packit Service df60bb
						if (im->trueColor) {
Packit Service df60bb
							/* 2.0.1: work around a gcc bug by being verbose.
Packit Service df60bb
							   TBB */
Packit Service df60bb
							int a = chunkBuf[chunkPos++] << 24;
Packit Service df60bb
							int r = chunkBuf[chunkPos++] << 16;
Packit Service df60bb
							int g = chunkBuf[chunkPos++] << 8;
Packit Service df60bb
							int b = chunkBuf[chunkPos++];
Packit Service df60bb
							/* 2.0.11: tpixels */
Packit Service df60bb
							im->tpixels[y][x] = a + r + g + b;
Packit Service df60bb
						} else {
Packit Service df60bb
							im->pixels[y][x] = chunkBuf[chunkPos++];
Packit Service df60bb
						}
Packit Service df60bb
					};
Packit Service df60bb
				};
Packit Service df60bb
				/*GD2_DBG(printf("\n")); */
Packit Service df60bb
			};
Packit Service df60bb
			chunkNum++;
Packit Service df60bb
		};
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	GD2_DBG (printf ("Freeing memory\n"));
Packit Service df60bb
Packit Service df60bb
	gdFree (chunkBuf);
Packit Service df60bb
	gdFree (compBuf);
Packit Service df60bb
	gdFree (chunkIdx);
Packit Service df60bb
Packit Service df60bb
	GD2_DBG (printf ("Done\n"));
Packit Service df60bb
Packit Service df60bb
	return im;
Packit Service df60bb
Packit Service df60bb
fail:
Packit Service df60bb
	gdImageDestroy (im);
Packit Service df60bb
	if (chunkBuf) {
Packit Service df60bb
		gdFree (chunkBuf);
Packit Service df60bb
	}
Packit Service df60bb
	if (compBuf) {
Packit Service df60bb
		gdFree (compBuf);
Packit Service df60bb
	}
Packit Service df60bb
	if (chunkIdx) {
Packit Service df60bb
		gdFree (chunkIdx);
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromGd2Part
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromGd2Part> is called to load parts of images from
Packit Service df60bb
    gd2 format files. Invoked in the same way as <gdImageCreateFromGd2>,
Packit Service df60bb
    but with extra parameters indicating the source (x, y) and
Packit Service df60bb
    width/height of the desired image. <gdImageCreateFromGd2Part>
Packit Service df60bb
    returns a <gdImagePtr> to the new image, or NULL if unable to load
Packit Service df60bb
    the image. The image must eventually be destroyed using
Packit Service df60bb
    <gdImageDestroy>.
Packit Service df60bb
Packit Service df60bb
  Variants:
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromGd2PartPtr> creates an image from GD2 data
Packit Service df60bb
    (i.e. the contents of a GD2 file) already in memory.
Packit Service df60bb
Packit Service df60bb
    <gdImageCreateFromGd2Ctx> reads in an image using the functions in
Packit Service df60bb
    a <gdIOCtx> struct.
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    infile      - The input FILE pointer
Packit Service df60bb
    srcx, srcy  - The source X and Y coordinates
Packit Service df60bb
    w, h        - The resulting image's width and height
Packit Service df60bb
Packit Service df60bb
  Returns:
Packit Service df60bb
Packit Service df60bb
    A pointer to the new image or NULL if an error occurred.
Packit Service df60bb
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewFileCtx (inFile);
Packit Service df60bb
Packit Service df60bb
	if (in == NULL) return NULL;
Packit Service df60bb
	im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h);
Packit Service df60bb
Packit Service df60bb
	in->gd_free (in);
Packit Service df60bb
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromGd2PartPtr
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    size        - size of GD data in bytes.
Packit Service df60bb
    data        - GD data (i.e. contents of a GIF file).
Packit Service df60bb
    srcx, srcy  - The source X and Y coordinates
Packit Service df60bb
    w, h        - The resulting image's width and height
Packit Service df60bb
Packit Service df60bb
  Reads in part of a GD2 image file stored from memory. See
Packit Service df60bb
  <gdImageCreateFromGd2Part>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, int w,
Packit Service df60bb
        int h)
Packit Service df60bb
{
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
	gdIOCtx *in = gdNewDynamicCtxEx (size, data, 0);
Packit Service df60bb
	if(!in)
Packit Service df60bb
		return 0;
Packit Service df60bb
	im = gdImageCreateFromGd2PartCtx (in, srcx, srcy, w, h);
Packit Service df60bb
	in->gd_free (in);
Packit Service df60bb
	return im;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
  Function: gdImageCreateFromGd2PartCtx
Packit Service df60bb
Packit Service df60bb
  Parameters:
Packit Service df60bb
Packit Service df60bb
    in          - The data source.
Packit Service df60bb
    srcx, srcy  - The source X and Y coordinates
Packit Service df60bb
    w, h        - The resulting image's width and height
Packit Service df60bb
Packit Service df60bb
  Reads in part of a GD2 data image file via a <gdIOCtx> struct.  See
Packit Service df60bb
  <gdImageCreateFromGd2Part>.
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
Packit Service df60bb
{
Packit Service df60bb
	int scx, scy, ecx, ecy, fsx, fsy;
Packit Service df60bb
	int nc, ncx, ncy, cs, cx, cy;
Packit Service df60bb
	int x, y, ylo, yhi, xlo, xhi;
Packit Service df60bb
	int dstart, dpos;
Packit Service df60bb
	int i;
Packit Service df60bb
	/* 2.0.12: unsigned is correct; fixes problems with color munging.
Packit Service df60bb
	   Thanks to Steven Brown. */
Packit Service df60bb
	unsigned int ch;
Packit Service df60bb
	int vers, fmt;
Packit Service df60bb
	t_chunk_info *chunkIdx = NULL;
Packit Service df60bb
	unsigned char *chunkBuf = NULL;
Packit Service df60bb
	int chunkNum;
Packit Service df60bb
	int chunkMax = 0;
Packit Service df60bb
	uLongf chunkLen;
Packit Service df60bb
	int chunkPos = 0;
Packit Service df60bb
	int compMax;
Packit Service df60bb
	char *compBuf = NULL;
Packit Service df60bb
Packit Service df60bb
	gdImagePtr im;
Packit Service df60bb
Packit Service df60bb
	/* */
Packit Service df60bb
	/* The next few lines are basically copied from gd2CreateFromFile */
Packit Service df60bb
	/* - we change the file size, so don't want to use the code directly. */
Packit Service df60bb
	/*   but we do need to know the file size. */
Packit Service df60bb
	/* */
Packit Service df60bb
	if (_gd2GetHeader (in, &fsx, &fsy, &cs, &vers, &fmt, &ncx, &ncy, &chunkIdx)
Packit Service df60bb
	        != 1) {
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	}
Packit Service df60bb
Packit Service df60bb
	GD2_DBG (printf ("File size is %dx%d\n", fsx, fsy));
Packit Service df60bb
Packit Service df60bb
	/* This is the difference - make a file based on size of chunks. */
Packit Service df60bb
	if (gd2_truecolor (fmt)) {
Packit Service df60bb
		im = gdImageCreateTrueColor (w, h);
Packit Service df60bb
	} else {
Packit Service df60bb
		im = gdImageCreate (w, h);
Packit Service df60bb
	}
Packit Service df60bb
	if (im == NULL) {
Packit Service df60bb
		goto fail1;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	if (!_gdGetColors (in, im, vers == 2)) {
Packit Service df60bb
		goto fail2;
Packit Service df60bb
	}
Packit Service df60bb
	GD2_DBG (printf ("Image palette completed: %d colours\n", im->colorsTotal));
Packit Service df60bb
Packit Service df60bb
	/* Process the header info */
Packit Service df60bb
	nc = ncx * ncy;
Packit Service df60bb
Packit Service df60bb
	if (gd2_compressed (fmt)) {
Packit Service df60bb
		/* Find the maximum compressed chunk size. */
Packit Service df60bb
		compMax = 0;
Packit Service df60bb
		for (i = 0; (i < nc); i++) {
Packit Service df60bb
			if (chunkIdx[i].size > compMax) {
Packit Service df60bb
				compMax = chunkIdx[i].size;
Packit Service df60bb
			};
Packit Service df60bb
		};
Packit Service df60bb
		compMax++;
Packit Service df60bb
Packit Service df60bb
		if (im->trueColor) {
Packit Service df60bb
			chunkMax = cs * cs * 4;
Packit Service df60bb
		} else {
Packit Service df60bb
			chunkMax = cs * cs;
Packit Service df60bb
		}
Packit Service df60bb
		chunkBuf = gdCalloc (chunkMax, 1);
Packit Service df60bb
		if (!chunkBuf) {
Packit Service df60bb
			goto fail2;
Packit Service df60bb
		}
Packit Service df60bb
		compBuf = gdCalloc (compMax, 1);
Packit Service df60bb
		if (!compBuf) {
Packit Service df60bb
			goto fail2;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/*      Don't bother with this... */
Packit Service df60bb
	/*      if ( (ncx != sx / cs) || (ncy != sy / cs)) { */
Packit Service df60bb
	/*              goto fail2; */
Packit Service df60bb
	/*      }; */
Packit Service df60bb
Packit Service df60bb
Packit Service df60bb
	/* Work out start/end chunks */
Packit Service df60bb
	scx = srcx / cs;
Packit Service df60bb
	scy = srcy / cs;
Packit Service df60bb
	if (scx < 0) {
Packit Service df60bb
		scx = 0;
Packit Service df60bb
	};
Packit Service df60bb
	if (scy < 0) {
Packit Service df60bb
		scy = 0;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	ecx = (srcx + w) / cs;
Packit Service df60bb
	ecy = (srcy + h) / cs;
Packit Service df60bb
	if (ecx >= ncx) {
Packit Service df60bb
		ecx = ncx - 1;
Packit Service df60bb
	};
Packit Service df60bb
	if (ecy >= ncy) {
Packit Service df60bb
		ecy = ncy - 1;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/* Remember file position of image data. */
Packit Service df60bb
	dstart = gdTell (in);
Packit Service df60bb
	GD2_DBG (printf ("Data starts at %d\n", dstart));
Packit Service df60bb
Packit Service df60bb
	/* Loop through the chunks. */
Packit Service df60bb
	for (cy = scy; (cy <= ecy); cy++) {
Packit Service df60bb
Packit Service df60bb
		ylo = cy * cs;
Packit Service df60bb
		yhi = ylo + cs;
Packit Service df60bb
		if (yhi > fsy) {
Packit Service df60bb
			yhi = fsy;
Packit Service df60bb
		};
Packit Service df60bb
Packit Service df60bb
		for (cx = scx; (cx <= ecx); cx++) {
Packit Service df60bb
Packit Service df60bb
			xlo = cx * cs;
Packit Service df60bb
			xhi = xlo + cs;
Packit Service df60bb
			if (xhi > fsx) {
Packit Service df60bb
				xhi = fsx;
Packit Service df60bb
			};
Packit Service df60bb
Packit Service df60bb
			GD2_DBG (printf
Packit Service df60bb
			         ("Processing Chunk (%d, %d), from %d to %d\n", cx, cy, ylo,
Packit Service df60bb
			          yhi));
Packit Service df60bb
Packit Service df60bb
			if (!gd2_compressed (fmt)) {
Packit Service df60bb
				GD2_DBG (printf ("Using raw format data\n"));
Packit Service df60bb
				if (im->trueColor) {
Packit Service df60bb
					dpos =
Packit Service df60bb
					    (cy * (cs * fsx) * 4 + cx * cs * (yhi - ylo) * 4) +
Packit Service df60bb
					    dstart;
Packit Service df60bb
				} else {
Packit Service df60bb
					dpos = cy * (cs * fsx) + cx * cs * (yhi - ylo) + dstart;
Packit Service df60bb
				}
Packit Service df60bb
				/* gd 2.0.11: gdSeek returns TRUE on success, not 0.
Packit Service df60bb
				   Longstanding bug. 01/16/03 */
Packit Service df60bb
				if (!gdSeek (in, dpos)) {
Packit Service df60bb
					gd_error("Seek error\n");
Packit Service df60bb
					goto fail2;
Packit Service df60bb
				};
Packit Service df60bb
				GD2_DBG (printf
Packit Service df60bb
				         ("Reading (%d, %d) from position %d\n", cx, cy,
Packit Service df60bb
				          dpos - dstart));
Packit Service df60bb
			} else {
Packit Service df60bb
				chunkNum = cx + cy * ncx;
Packit Service df60bb
Packit Service df60bb
				chunkLen = chunkMax;
Packit Service df60bb
				if (!_gd2ReadChunk (chunkIdx[chunkNum].offset,
Packit Service df60bb
				                    compBuf,
Packit Service df60bb
				                    chunkIdx[chunkNum].size,
Packit Service df60bb
				                    (char *) chunkBuf, &chunkLen, in)) {
Packit Service df60bb
					printf ("Error reading comproessed chunk\n");
Packit Service df60bb
					goto fail2;
Packit Service df60bb
				};
Packit Service df60bb
				chunkPos = 0;
Packit Service df60bb
				GD2_DBG (printf
Packit Service df60bb
				         ("Reading (%d, %d) from chunk %d\n", cx, cy,
Packit Service df60bb
				          chunkNum));
Packit Service df60bb
			};
Packit Service df60bb
Packit Service df60bb
			GD2_DBG (printf
Packit Service df60bb
			         ("   into (%d, %d) - (%d, %d)\n", xlo, ylo, xhi, yhi));
Packit Service df60bb
			for (y = ylo; (y < yhi); y++) {
Packit Service df60bb
Packit Service df60bb
				for (x = xlo; x < xhi; x++) {
Packit Service df60bb
					if (!gd2_compressed (fmt)) {
Packit Service df60bb
						if (im->trueColor) {
Packit Service df60bb
							if (!gdGetInt ((int *) &ch, in)) {
Packit Service df60bb
								ch = 0;
Packit Service df60bb
								/*printf("EOF while reading file\n"); */
Packit Service df60bb
								/*goto fail2; */
Packit Service df60bb
							}
Packit Service df60bb
						} else {
Packit Service df60bb
							ch = gdGetC (in);
Packit Service df60bb
							if ((int) ch == EOF) {
Packit Service df60bb
								ch = 0;
Packit Service df60bb
								/*printf("EOF while reading file\n"); */
Packit Service df60bb
								/*goto fail2; */
Packit Service df60bb
							}
Packit Service df60bb
						}
Packit Service df60bb
					} else {
Packit Service df60bb
						if (im->trueColor) {
Packit Service df60bb
							ch = chunkBuf[chunkPos++];
Packit Service df60bb
							ch = (ch << 8) + chunkBuf[chunkPos++];
Packit Service df60bb
							ch = (ch << 8) + chunkBuf[chunkPos++];
Packit Service df60bb
							ch = (ch << 8) + chunkBuf[chunkPos++];
Packit Service df60bb
						} else {
Packit Service df60bb
							ch = chunkBuf[chunkPos++];
Packit Service df60bb
						}
Packit Service df60bb
					};
Packit Service df60bb
Packit Service df60bb
					/* Only use a point that is in the image. */
Packit Service df60bb
					if ((x >= srcx) && (x < (srcx + w)) && (x < fsx) && (x >= 0)
Packit Service df60bb
					        && (y >= srcy) && (y < (srcy + h)) && (y < fsy)
Packit Service df60bb
					        && (y >= 0)) {
Packit Service df60bb
						/* 2.0.11: tpixels */
Packit Service df60bb
						if (im->trueColor) {
Packit Service df60bb
							im->tpixels[y - srcy][x - srcx] = ch;
Packit Service df60bb
						} else {
Packit Service df60bb
							im->pixels[y - srcy][x - srcx] = ch;
Packit Service df60bb
						}
Packit Service df60bb
					}
Packit Service df60bb
				};
Packit Service df60bb
			};
Packit Service df60bb
		};
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	gdFree (chunkBuf);
Packit Service df60bb
	gdFree (compBuf);
Packit Service df60bb
	gdFree (chunkIdx);
Packit Service df60bb
Packit Service df60bb
	return im;
Packit Service df60bb
Packit Service df60bb
fail2:
Packit Service df60bb
	gdImageDestroy (im);
Packit Service df60bb
fail1:
Packit Service df60bb
	if (chunkBuf) {
Packit Service df60bb
		gdFree (chunkBuf);
Packit Service df60bb
	}
Packit Service df60bb
	if (compBuf) {
Packit Service df60bb
		gdFree (compBuf);
Packit Service df60bb
	}
Packit Service df60bb
	if (chunkIdx) {
Packit Service df60bb
		gdFree (chunkIdx);
Packit Service df60bb
	}
Packit Service df60bb
	return 0;
Packit Service df60bb
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static void
Packit Service df60bb
_gd2PutHeader (gdImagePtr im, gdIOCtx * out, int cs, int fmt, int cx, int cy)
Packit Service df60bb
{
Packit Service df60bb
	int i;
Packit Service df60bb
Packit Service df60bb
	/* Send the gd2 id, to verify file format. */
Packit Service df60bb
	for (i = 0; i < 4; i++) {
Packit Service df60bb
		gdPutC ((unsigned char) (GD2_ID[i]), out);
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/* */
Packit Service df60bb
	/* We put the version info first, so future versions can easily change header info. */
Packit Service df60bb
	/* */
Packit Service df60bb
	gdPutWord (GD2_VERS, out);
Packit Service df60bb
	gdPutWord (im->sx, out);
Packit Service df60bb
	gdPutWord (im->sy, out);
Packit Service df60bb
	gdPutWord (cs, out);
Packit Service df60bb
	gdPutWord (fmt, out);
Packit Service df60bb
	gdPutWord (cx, out);
Packit Service df60bb
	gdPutWord (cy, out);
Packit Service df60bb
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
static void
Packit Service df60bb
_gdImageGd2 (gdImagePtr im, gdIOCtx * out, int cs, int fmt)
Packit Service df60bb
{
Packit Service df60bb
	int ncx, ncy, cx, cy;
Packit Service df60bb
	int x, y, ylo, yhi, xlo, xhi;
Packit Service df60bb
	int chunkLen;
Packit Service df60bb
	int chunkNum = 0;
Packit Service df60bb
	char *chunkData = NULL;	/* So we can gdFree it with impunity. */
Packit Service df60bb
	char *compData = NULL;	/* So we can gdFree it with impunity. */
Packit Service df60bb
	uLongf compLen;
Packit Service df60bb
	int idxPos = 0;
Packit Service df60bb
	int idxSize;
Packit Service df60bb
	t_chunk_info *chunkIdx = NULL;
Packit Service df60bb
	int posSave;
Packit Service df60bb
	int bytesPerPixel = im->trueColor ? 4 : 1;
Packit Service df60bb
	int compMax = 0;
Packit Service df60bb
Packit Service df60bb
	/*printf("Trying to write GD2 file\n"); */
Packit Service df60bb
Packit Service df60bb
	/* */
Packit Service df60bb
	/* Force fmt to a valid value since we don't return anything. */
Packit Service df60bb
	/* */
Packit Service df60bb
	if ((fmt != GD2_FMT_RAW) && (fmt != GD2_FMT_COMPRESSED)) {
Packit Service df60bb
		fmt = GD2_FMT_COMPRESSED;
Packit Service df60bb
	};
Packit Service df60bb
	if (im->trueColor) {
Packit Service df60bb
		fmt += 2;
Packit Service df60bb
	}
Packit Service df60bb
	/* */
Packit Service df60bb
	/* Make sure chunk size is valid. These are arbitrary values; 64 because it seems */
Packit Service df60bb
	/* a little silly to expect performance improvements on a 64x64 bit scale, and  */
Packit Service df60bb
	/* 4096 because we buffer one chunk, and a 16MB buffer seems a little large - it may be */
Packit Service df60bb
	/* OK for one user, but for another to read it, they require the buffer. */
Packit Service df60bb
	/* */
Packit Service df60bb
	if (cs == 0) {
Packit Service df60bb
		cs = GD2_CHUNKSIZE;
Packit Service df60bb
	} else if (cs < GD2_CHUNKSIZE_MIN) {
Packit Service df60bb
		cs = GD2_CHUNKSIZE_MIN;
Packit Service df60bb
	} else if (cs > GD2_CHUNKSIZE_MAX) {
Packit Service df60bb
		cs = GD2_CHUNKSIZE_MAX;
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/* Work out number of chunks. */
Packit Service df60bb
	ncx = (im->sx + cs - 1) / cs;
Packit Service df60bb
	ncy = (im->sy + cs - 1) / cs;
Packit Service df60bb
Packit Service df60bb
	/* Write the standard header. */
Packit Service df60bb
	_gd2PutHeader (im, out, cs, fmt, ncx, ncy);
Packit Service df60bb
Packit Service df60bb
	if (gd2_compressed (fmt)) {
Packit Service df60bb
		/* */
Packit Service df60bb
		/* Work out size of buffer for compressed data, If CHUNKSIZE is large, */
Packit Service df60bb
		/* then these will be large! */
Packit Service df60bb
		/* */
Packit Service df60bb
		/* The zlib notes say output buffer size should be (input size) * 1.01 * 12 */
Packit Service df60bb
		/* - we'll use 1.02 to be paranoid. */
Packit Service df60bb
		/* */
Packit Service df60bb
		compMax = cs * bytesPerPixel * cs * 1.02 + 12;
Packit Service df60bb
Packit Service df60bb
		/* */
Packit Service df60bb
		/* Allocate the buffers.  */
Packit Service df60bb
		/* */
Packit Service df60bb
		chunkData = gdCalloc (cs * bytesPerPixel * cs, 1);
Packit Service df60bb
		if (!chunkData) {
Packit Service df60bb
			goto fail;
Packit Service df60bb
		}
Packit Service df60bb
		compData = gdCalloc (compMax, 1);
Packit Service df60bb
		if (!compData) {
Packit Service df60bb
			goto fail;
Packit Service df60bb
		}
Packit Service df60bb
Packit Service df60bb
		/* */
Packit Service df60bb
		/* Save the file position of chunk index, and allocate enough space for */
Packit Service df60bb
		/* each chunk_info block . */
Packit Service df60bb
		/* */
Packit Service df60bb
		idxPos = gdTell (out);
Packit Service df60bb
		idxSize = ncx * ncy * sizeof (t_chunk_info);
Packit Service df60bb
		GD2_DBG (printf ("Index size is %d\n", idxSize));
Packit Service df60bb
		gdSeek (out, idxPos + idxSize);
Packit Service df60bb
Packit Service df60bb
		chunkIdx = gdCalloc (idxSize * sizeof (t_chunk_info), 1);
Packit Service df60bb
		if (!chunkIdx) {
Packit Service df60bb
			goto fail;
Packit Service df60bb
		}
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	_gdPutColors (im, out);
Packit Service df60bb
Packit Service df60bb
	GD2_DBG (printf ("Size: %dx%d\n", im->sx, im->sy));
Packit Service df60bb
	GD2_DBG (printf ("Chunks: %dx%d\n", ncx, ncy));
Packit Service df60bb
Packit Service df60bb
	for (cy = 0; (cy < ncy); cy++) {
Packit Service df60bb
		for (cx = 0; (cx < ncx); cx++) {
Packit Service df60bb
Packit Service df60bb
			ylo = cy * cs;
Packit Service df60bb
			yhi = ylo + cs;
Packit Service df60bb
			if (yhi > im->sy) {
Packit Service df60bb
				yhi = im->sy;
Packit Service df60bb
			};
Packit Service df60bb
Packit Service df60bb
			GD2_DBG (printf
Packit Service df60bb
			         ("Processing Chunk (%dx%d), y from %d to %d\n", cx, cy,
Packit Service df60bb
			          ylo, yhi));
Packit Service df60bb
			chunkLen = 0;
Packit Service df60bb
			for (y = ylo; (y < yhi); y++) {
Packit Service df60bb
Packit Service df60bb
				/*GD2_DBG(printf("y=%d: ",y)); */
Packit Service df60bb
Packit Service df60bb
				xlo = cx * cs;
Packit Service df60bb
				xhi = xlo + cs;
Packit Service df60bb
				if (xhi > im->sx) {
Packit Service df60bb
					xhi = im->sx;
Packit Service df60bb
				};
Packit Service df60bb
Packit Service df60bb
				if (gd2_compressed (fmt)) {
Packit Service df60bb
					for (x = xlo; x < xhi; x++) {
Packit Service df60bb
						/* 2.0.11: use truecolor pixel array. TBB */
Packit Service df60bb
						/*GD2_DBG(printf("%d...",x)); */
Packit Service df60bb
						if (im->trueColor) {
Packit Service df60bb
							int p = im->tpixels[y][x];
Packit Service df60bb
							chunkData[chunkLen++] = gdTrueColorGetAlpha (p);
Packit Service df60bb
							chunkData[chunkLen++] = gdTrueColorGetRed (p);
Packit Service df60bb
							chunkData[chunkLen++] = gdTrueColorGetGreen (p);
Packit Service df60bb
							chunkData[chunkLen++] = gdTrueColorGetBlue (p);
Packit Service df60bb
						} else {
Packit Service df60bb
							int p = im->pixels[y][x];
Packit Service df60bb
							chunkData[chunkLen++] = p;
Packit Service df60bb
						}
Packit Service df60bb
					};
Packit Service df60bb
				} else {
Packit Service df60bb
					for (x = xlo; x < xhi; x++) {
Packit Service df60bb
						/*GD2_DBG(printf("%d, ",x)); */
Packit Service df60bb
Packit Service df60bb
						if (im->trueColor) {
Packit Service df60bb
							gdPutInt (im->tpixels[y][x], out);
Packit Service df60bb
						} else {
Packit Service df60bb
							gdPutC ((unsigned char) im->pixels[y][x], out);
Packit Service df60bb
						}
Packit Service df60bb
					};
Packit Service df60bb
				};
Packit Service df60bb
				/*GD2_DBG(printf("y=%d done.\n",y)); */
Packit Service df60bb
			};
Packit Service df60bb
			if (gd2_compressed (fmt)) {
Packit Service df60bb
				compLen = compMax;
Packit Service df60bb
				if (compress ((unsigned char *)
Packit Service df60bb
				              &compData[0], &compLen,
Packit Service df60bb
				              (unsigned char *) &chunkData[0],
Packit Service df60bb
				              chunkLen) != Z_OK) {
Packit Service df60bb
					printf ("Error from compressing\n");
Packit Service df60bb
				} else {
Packit Service df60bb
					chunkIdx[chunkNum].offset = gdTell (out);
Packit Service df60bb
					chunkIdx[chunkNum++].size = compLen;
Packit Service df60bb
					GD2_DBG (printf
Packit Service df60bb
					         ("Chunk %d size %d offset %d\n", chunkNum,
Packit Service df60bb
					          chunkIdx[chunkNum - 1].size,
Packit Service df60bb
					          chunkIdx[chunkNum - 1].offset));
Packit Service df60bb
Packit Service df60bb
					if (gdPutBuf (compData, compLen, out) <= 0) {
Packit Service df60bb
						gd_error("gd write error\n");
Packit Service df60bb
					};
Packit Service df60bb
				};
Packit Service df60bb
			};
Packit Service df60bb
		};
Packit Service df60bb
	};
Packit Service df60bb
	if (gd2_compressed (fmt)) {
Packit Service df60bb
		/* Save the position, write the index, restore position (paranoia). */
Packit Service df60bb
		GD2_DBG (printf ("Seeking %d to write index\n", idxPos));
Packit Service df60bb
		posSave = gdTell (out);
Packit Service df60bb
		gdSeek (out, idxPos);
Packit Service df60bb
		GD2_DBG (printf ("Writing index\n"));
Packit Service df60bb
		for (x = 0; x < chunkNum; x++) {
Packit Service df60bb
			GD2_DBG (printf
Packit Service df60bb
			         ("Chunk %d size %d offset %d\n", x, chunkIdx[x].size,
Packit Service df60bb
			          chunkIdx[x].offset));
Packit Service df60bb
			gdPutInt (chunkIdx[x].offset, out);
Packit Service df60bb
			gdPutInt (chunkIdx[x].size, out);
Packit Service df60bb
		};
Packit Service df60bb
		/* We don't use fwrite for *endian reasons. */
Packit Service df60bb
		/*fwrite(chunkIdx, sizeof(int)*2, chunkNum, out); */
Packit Service df60bb
		gdSeek (out, posSave);
Packit Service df60bb
	};
Packit Service df60bb
Packit Service df60bb
	/*printf("Memory block size is %d\n",gdTell(out)); */
Packit Service df60bb
fail:
Packit Service df60bb
	GD2_DBG (printf ("Freeing memory\n"));
Packit Service df60bb
Packit Service df60bb
	if (chunkData) {
Packit Service df60bb
		gdFree (chunkData);
Packit Service df60bb
	}
Packit Service df60bb
	if (compData) {
Packit Service df60bb
		gdFree (compData);
Packit Service df60bb
	}
Packit Service df60bb
	if (chunkIdx) {
Packit Service df60bb
		gdFree (chunkIdx);
Packit Service df60bb
	}
Packit Service df60bb
	GD2_DBG (printf ("Done\n"));
Packit Service df60bb
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageGd2
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void) gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
Packit Service df60bb
{
Packit Service df60bb
	gdIOCtx *out = gdNewFileCtx (outFile);
Packit Service df60bb
	if (out == NULL) return;
Packit Service df60bb
	_gdImageGd2 (im, out, cs, fmt);
Packit Service df60bb
	out->gd_free (out);
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
/*
Packit Service df60bb
	Function: gdImageGd2Ptr
Packit Service df60bb
*/
Packit Service df60bb
BGD_DECLARE(void *) gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
Packit Service df60bb
{
Packit Service df60bb
	void *rv;
Packit Service df60bb
	gdIOCtx *out = gdNewDynamicCtx (2048, NULL);
Packit Service df60bb
	if (out == NULL) return NULL;
Packit Service df60bb
	_gdImageGd2 (im, out, cs, fmt);
Packit Service df60bb
	rv = gdDPExtractData (out, size);
Packit Service df60bb
	out->gd_free (out);
Packit Service df60bb
	return rv;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
#else /* no HAVE_LIBZ */
Packit Service df60bb
static void _noLibzError (void)
Packit Service df60bb
{
Packit Service df60bb
	gd_error("GD2 support is not available - no libz\n");
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2 (FILE * inFile)
Packit Service df60bb
{
Packit Service df60bb
	_noLibzError();
Packit Service df60bb
	return NULL;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ctx (gdIOCtxPtr in)
Packit Service df60bb
{
Packit Service df60bb
	_noLibzError();
Packit Service df60bb
	return NULL;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Part (FILE * inFile, int srcx, int srcy, int w, int h)
Packit Service df60bb
{
Packit Service df60bb
	_noLibzError();
Packit Service df60bb
	return NULL;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2Ptr (int size, void *data)
Packit Service df60bb
{
Packit Service df60bb
	_noLibzError();
Packit Service df60bb
	return NULL;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartCtx (gdIOCtx * in, int srcx, int srcy, int w, int h)
Packit Service df60bb
{
Packit Service df60bb
	_noLibzError();
Packit Service df60bb
	return NULL;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(gdImagePtr) gdImageCreateFromGd2PartPtr (int size, void *data, int srcx, int srcy, int w,
Packit Service df60bb
        int h)
Packit Service df60bb
{
Packit Service df60bb
	_noLibzError();
Packit Service df60bb
	return NULL;
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(void) gdImageGd2 (gdImagePtr im, FILE * outFile, int cs, int fmt)
Packit Service df60bb
{
Packit Service df60bb
	_noLibzError();
Packit Service df60bb
}
Packit Service df60bb
Packit Service df60bb
BGD_DECLARE(void *) gdImageGd2Ptr (gdImagePtr im, int cs, int fmt, int *size)
Packit Service df60bb
{
Packit Service df60bb
	_noLibzError();
Packit Service df60bb
	return NULL;
Packit Service df60bb
}
Packit Service df60bb
#endif /* HAVE_LIBZ */