Blame src/gd_gif_in.c

Packit ed3af9
/**
Packit ed3af9
 * File: GIF Input
Packit ed3af9
 *
Packit ed3af9
 * Read GIF images.
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
#ifdef HAVE_CONFIG_H
Packit ed3af9
#include "config.h"
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#include <stdio.h>
Packit ed3af9
#include <math.h>
Packit ed3af9
#include <string.h>
Packit ed3af9
#include <stdlib.h>
Packit ed3af9
#include "gd.h"
Packit ed3af9
Packit ed3af9
/* Used only when debugging GIF compression code */
Packit ed3af9
/* #define DEBUGGING_ENVARS */
Packit ed3af9
Packit ed3af9
#ifdef DEBUGGING_ENVARS
Packit ed3af9
Packit ed3af9
static int verbose_set = 0;
Packit ed3af9
static int verbose;
Packit ed3af9
Packit ed3af9
#define VERBOSE (verbose_set ? verbose : set_verbose())
Packit ed3af9
Packit ed3af9
static int set_verbose(void)
Packit ed3af9
{
Packit ed3af9
	verbose = !!getenv("GIF_VERBOSE");
Packit ed3af9
	verbose_set = 1;
Packit ed3af9
	return(verbose);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
#else
Packit ed3af9
Packit ed3af9
#define VERBOSE	0
Packit ed3af9
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#define MAXCOLORMAPSIZE	256
Packit ed3af9
Packit ed3af9
#define TRUE	1
Packit ed3af9
#define FALSE	0
Packit ed3af9
Packit ed3af9
#define CM_RED		0
Packit ed3af9
#define CM_GREEN	1
Packit ed3af9
#define CM_BLUE		2
Packit ed3af9
Packit ed3af9
#define MAX_LWZ_BITS	12
Packit ed3af9
Packit ed3af9
#define INTERLACE		0x40
Packit ed3af9
#define LOCALCOLORMAP	0x80
Packit ed3af9
Packit ed3af9
#define BitSet(byte, bit)	(((byte) & (bit)) == (bit))
Packit ed3af9
Packit ed3af9
#define ReadOK(file, buffer, len) (gdGetBuf(buffer, len, file) > 0)
Packit ed3af9
Packit ed3af9
#define LM_to_uint(a, b)	(((b)<<8)|(a))
Packit ed3af9
Packit ed3af9
/* We may eventually want to use this information, but def it out for now */
Packit ed3af9
#if 0
Packit ed3af9
static struct {
Packit ed3af9
	unsigned int    Width;
Packit ed3af9
	unsigned int    Height;
Packit ed3af9
	unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
Packit ed3af9
	unsigned int    BitPixel;
Packit ed3af9
	unsigned int    ColorResolution;
Packit ed3af9
	unsigned int    Background;
Packit ed3af9
	unsigned int    AspectRatio;
Packit ed3af9
} GifScreen;
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#if 0
Packit ed3af9
static struct {
Packit ed3af9
	int     transparent;
Packit ed3af9
	int     delayTime;
Packit ed3af9
	int     inputFlag;
Packit ed3af9
	int     disposal;
Packit ed3af9
} Gif89 = { -1, -1, -1, 0 };
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#define STACK_SIZE ((1<<(MAX_LWZ_BITS))*2)
Packit ed3af9
Packit ed3af9
#define CSD_BUF_SIZE 280
Packit ed3af9
Packit ed3af9
typedef struct {
Packit ed3af9
	unsigned char buf[CSD_BUF_SIZE];
Packit ed3af9
	int curbit;
Packit ed3af9
	int lastbit;
Packit ed3af9
	int done;
Packit ed3af9
	int last_byte;
Packit ed3af9
} CODE_STATIC_DATA;
Packit ed3af9
Packit ed3af9
typedef struct {
Packit ed3af9
	int fresh;
Packit ed3af9
	int code_size, set_code_size;
Packit ed3af9
	int max_code, max_code_size;
Packit ed3af9
	int firstcode, oldcode;
Packit ed3af9
	int clear_code, end_code;
Packit ed3af9
	int table[2][(1<< MAX_LWZ_BITS)];
Packit ed3af9
	int stack[STACK_SIZE], *sp;
Packit ed3af9
	CODE_STATIC_DATA scd;
Packit ed3af9
} LZW_STATIC_DATA;
Packit ed3af9
Packit ed3af9
static int ReadColorMap (gdIOCtx *fd, int number, unsigned char (*buffer)[256]);
Packit ed3af9
static int DoExtension (gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP);
Packit ed3af9
static int GetDataBlock (gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP);
Packit ed3af9
static int GetCode (gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP);
Packit ed3af9
static int LWZReadByte (gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP);
Packit ed3af9
Packit ed3af9
static void ReadImage (gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP); /*1.4//, int ignore); */
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageCreateFromGif
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromGif> is called to load images from GIF format
Packit ed3af9
    files. Invoke <gdImageCreateFromGif> with an already opened
Packit ed3af9
    pointer to a file containing the desired
Packit ed3af9
    image.
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromGif> returns a <gdImagePtr> to the new image, or
Packit ed3af9
    NULL if unable to load the image (most often because the file is
Packit ed3af9
    corrupt or does not contain a GIF image). <gdImageCreateFromGif>
Packit ed3af9
    does not close the file. You can inspect the sx and sy members of
Packit ed3af9
    the image to determine its size. The image must eventually be
Packit ed3af9
    destroyed using <gdImageDestroy>.
Packit ed3af9
Packit ed3af9
  Variants:
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromGifPtr> creates an image from GIF data (i.e. the
Packit ed3af9
    contents of a GIF file) already in memory.
Packit ed3af9
Packit ed3af9
    <gdImageCreateFromGifCtx> reads in an image using the functions in
Packit ed3af9
    a <gdIOCtx> struct.
Packit ed3af9
Packit ed3af9
  Parameters:
Packit ed3af9
Packit ed3af9
    infile - The input FILE pointer
Packit ed3af9
Packit ed3af9
  Returns:
Packit ed3af9
Packit ed3af9
    A pointer to the new image or NULL if an error occurred.
Packit ed3af9
Packit ed3af9
  Example:
Packit ed3af9
Packit ed3af9
    > gdImagePtr im;
Packit ed3af9
    > ... inside a function ...
Packit ed3af9
    > FILE *in;
Packit ed3af9
    > in = fopen("mygif.gif", "rb");
Packit ed3af9
    > im = gdImageCreateFromGif(in);
Packit ed3af9
    > fclose(in);
Packit ed3af9
    > // ... Use the image ... 
Packit ed3af9
    > gdImageDestroy(im);
Packit ed3af9
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageCreateFromGif(FILE *fdFile)
Packit ed3af9
{
Packit ed3af9
	gdIOCtx *fd = gdNewFileCtx(fdFile);
Packit ed3af9
	gdImagePtr im;
Packit ed3af9
Packit ed3af9
	if (fd == NULL) return NULL;
Packit ed3af9
	im = gdImageCreateFromGifCtx(fd);
Packit ed3af9
Packit ed3af9
	fd->gd_free(fd);
Packit ed3af9
Packit ed3af9
	return im;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageCreateFromGifPtr
Packit ed3af9
Packit ed3af9
  Parameters:
Packit ed3af9
Packit ed3af9
    size - size of GIF data in bytes.
Packit ed3af9
    data - GIF data (i.e. contents of a GIF file).
Packit ed3af9
Packit ed3af9
  See <gdImageCreateFromGif>.
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageCreateFromGifPtr (int size, void *data)
Packit ed3af9
{
Packit ed3af9
	gdImagePtr im;
Packit ed3af9
	gdIOCtx *in = gdNewDynamicCtxEx(size, data, 0);
Packit ed3af9
	if(!in) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
	im = gdImageCreateFromGifCtx(in);
Packit ed3af9
	in->gd_free(in);
Packit ed3af9
	return im;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
  Function: gdImageCreateFromGifCtx
Packit ed3af9
Packit ed3af9
  See <gdImageCreateFromGif>.
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdImagePtr) gdImageCreateFromGifCtx(gdIOCtxPtr fd)
Packit ed3af9
{
Packit ed3af9
	int BitPixel;
Packit ed3af9
#if 0
Packit ed3af9
	int ColorResolution;
Packit ed3af9
	int Background;
Packit ed3af9
	int AspectRatio;
Packit ed3af9
#endif
Packit ed3af9
	int Transparent = (-1);
Packit ed3af9
	unsigned char buf[16];
Packit ed3af9
	unsigned char c;
Packit ed3af9
	unsigned char ColorMap[3][MAXCOLORMAPSIZE];
Packit ed3af9
	unsigned char localColorMap[3][MAXCOLORMAPSIZE];
Packit ed3af9
	int imw, imh, screen_width, screen_height;
Packit ed3af9
	int useGlobalColormap;
Packit ed3af9
	int bitPixel, i;
Packit ed3af9
	/*1.4//int             imageCount = 0; */
Packit ed3af9
	/* 2.0.28: threadsafe storage */
Packit ed3af9
	int ZeroDataBlock = FALSE;
Packit ed3af9
	int haveGlobalColormap;
Packit ed3af9
Packit ed3af9
	gdImagePtr im = 0;
Packit ed3af9
Packit ed3af9
	memset(ColorMap, 0, 3 * MAXCOLORMAPSIZE);
Packit ed3af9
	memset(localColorMap, 0, 3 * MAXCOLORMAPSIZE);
Packit ed3af9
Packit ed3af9
	if(!ReadOK(fd, buf, 6)) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if(strncmp((char *)buf, "GIF", 3) != 0) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if(memcmp((char *)buf + 3, "87a", 3) == 0) {
Packit ed3af9
		/* GIF87a */
Packit ed3af9
	} else if(memcmp((char *)buf + 3, "89a", 3) == 0) {
Packit ed3af9
		/* GIF89a */
Packit ed3af9
	} else {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if(!ReadOK(fd, buf, 7)) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	BitPixel = 2 << (buf[4] & 0x07);
Packit ed3af9
#if 0
Packit ed3af9
	ColorResolution = (int) (((buf[4]&0x70)>>3)+1);
Packit ed3af9
	Background = buf[5];
Packit ed3af9
	AspectRatio = buf[6];
Packit ed3af9
#endif
Packit ed3af9
	screen_width = imw = LM_to_uint(buf[0], buf[1]);
Packit ed3af9
	screen_height = imh = LM_to_uint(buf[2], buf[3]);
Packit ed3af9
Packit ed3af9
	haveGlobalColormap = BitSet(buf[4], LOCALCOLORMAP); /* Global Colormap */
Packit ed3af9
	if(haveGlobalColormap) {
Packit ed3af9
		if(ReadColorMap(fd, BitPixel, ColorMap)) {
Packit ed3af9
			return 0;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	for (;;) {
Packit ed3af9
		int top, left;
Packit ed3af9
		int width, height;
Packit ed3af9
Packit ed3af9
		if(!ReadOK(fd, &c, 1)) {
Packit ed3af9
			return 0;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if (c == ';') { /* GIF terminator */
Packit ed3af9
			goto terminated;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(c == '!') { /* Extension */
Packit ed3af9
			if(!ReadOK(fd, &c, 1)) {
Packit ed3af9
				return 0;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			DoExtension(fd, c, &Transparent, &ZeroDataBlock);
Packit ed3af9
			continue;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(c != ',') { /* Not a valid start character */
Packit ed3af9
			continue;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		/*1.4//++imageCount; */
Packit ed3af9
Packit ed3af9
		if(!ReadOK(fd, buf, 9)) {
Packit ed3af9
			return 0;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		useGlobalColormap = !BitSet(buf[8], LOCALCOLORMAP);
Packit ed3af9
Packit ed3af9
		bitPixel = 1 << ((buf[8] & 0x07) + 1);
Packit ed3af9
		left = LM_to_uint(buf[0], buf[1]);
Packit ed3af9
		top = LM_to_uint(buf[2], buf[3]);
Packit ed3af9
		width = LM_to_uint(buf[4], buf[5]);
Packit ed3af9
		height = LM_to_uint(buf[6], buf[7]);
Packit ed3af9
Packit ed3af9
		if(((left + width) > screen_width) || ((top + height) > screen_height)) {
Packit ed3af9
			if(VERBOSE) {
Packit ed3af9
				printf("Frame is not confined to screen dimension.\n");
Packit ed3af9
			}
Packit ed3af9
			return 0;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(!(im = gdImageCreate(width, height))) {
Packit ed3af9
			return 0;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		im->interlace = BitSet(buf[8], INTERLACE);
Packit ed3af9
		if(!useGlobalColormap) {
Packit ed3af9
			if(ReadColorMap(fd, bitPixel, localColorMap)) {
Packit ed3af9
				gdImageDestroy(im);
Packit ed3af9
				return 0;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			ReadImage(im, fd, width, height, localColorMap, BitSet(buf[8], INTERLACE), &ZeroDataBlock);
Packit ed3af9
		} else {
Packit ed3af9
			if(!haveGlobalColormap) {
Packit ed3af9
				gdImageDestroy(im);
Packit ed3af9
				return 0;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			ReadImage(im, fd, width, height, ColorMap, BitSet(buf[8], INTERLACE), &ZeroDataBlock);
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(Transparent != (-1)) {
Packit ed3af9
			gdImageColorTransparent(im, Transparent);
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		goto terminated;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
terminated:
Packit ed3af9
	/* Terminator before any image was declared! */
Packit ed3af9
	if(!im) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* Check for open colors at the end, so
Packit ed3af9
	 * we can reduce colorsTotal and ultimately
Packit ed3af9
	 * BitsPerPixel */
Packit ed3af9
	for(i = im->colorsTotal - 1; i >= 0; i--) {
Packit ed3af9
		if(im->open[i]) {
Packit ed3af9
			im->colorsTotal--;
Packit ed3af9
		} else {
Packit ed3af9
			break;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit Service f1eddf
	if(!im->colorsTotal) {
Packit Service f1eddf
		gdImageDestroy(im);
Packit Service f1eddf
		return 0;
Packit Service f1eddf
	}
Packit Service f1eddf
Packit ed3af9
	return im;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
ReadColorMap(gdIOCtx *fd, int number, unsigned char (*buffer)[256])
Packit ed3af9
{
Packit ed3af9
	int i;
Packit ed3af9
	unsigned char rgb[3];
Packit ed3af9
Packit ed3af9
	for(i = 0; i < number; ++i) {
Packit ed3af9
		if(!ReadOK(fd, rgb, sizeof(rgb))) {
Packit ed3af9
			return TRUE;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		buffer[CM_RED][i] = rgb[0];
Packit ed3af9
		buffer[CM_GREEN][i] = rgb[1];
Packit ed3af9
		buffer[CM_BLUE][i] = rgb[2];
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return FALSE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
DoExtension(gdIOCtx *fd, int label, int *Transparent, int *ZeroDataBlockP)
Packit ed3af9
{
Packit ed3af9
	unsigned char buf[256];
Packit ed3af9
Packit ed3af9
	switch(label) {
Packit ed3af9
	case 0xf9: /* Graphic Control Extension */
Packit ed3af9
		memset(buf, 0, 4); /* initialize a few bytes in the case the next function fails */
Packit ed3af9
		(void) GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP);
Packit ed3af9
#if 0
Packit ed3af9
		Gif89.disposal  = (buf[0] >> 2) & 0x7;
Packit ed3af9
		Gif89.inputFlag = (buf[0] >> 1) & 0x1;
Packit ed3af9
		Gif89.delayTime = LM_to_uint(buf[1], buf[2]);
Packit ed3af9
#endif
Packit ed3af9
		if((buf[0] & 0x1) != 0) {
Packit ed3af9
			*Transparent = buf[3];
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		while(GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0);
Packit ed3af9
Packit ed3af9
		return FALSE;
Packit ed3af9
Packit ed3af9
	default:
Packit ed3af9
		break;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	while(GetDataBlock(fd, (unsigned char*) buf, ZeroDataBlockP) > 0);
Packit ed3af9
Packit ed3af9
	return FALSE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
GetDataBlock_(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
Packit ed3af9
{
Packit ed3af9
	unsigned char count;
Packit ed3af9
Packit ed3af9
	if(!ReadOK(fd, &count, 1)) {
Packit ed3af9
		return -1;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	*ZeroDataBlockP = count == 0;
Packit ed3af9
Packit ed3af9
	if((count != 0) && (!ReadOK(fd, buf, count))) {
Packit ed3af9
		return -1;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return count;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
GetDataBlock(gdIOCtx *fd, unsigned char *buf, int *ZeroDataBlockP)
Packit ed3af9
{
Packit ed3af9
	int rv, i;
Packit ed3af9
Packit ed3af9
	rv = GetDataBlock_(fd,buf, ZeroDataBlockP);
Packit ed3af9
Packit ed3af9
	if(VERBOSE) {
Packit ed3af9
		printf("[GetDataBlock returning %d",rv);
Packit ed3af9
		if(rv > 0) {
Packit ed3af9
			printf(":");
Packit ed3af9
			for(i = 0; i < rv; i++) {
Packit ed3af9
				printf(" %02x",buf[i]);
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
		printf("]\n");
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return rv;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
GetCode_(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
Packit ed3af9
{
Packit ed3af9
	int i, j, ret;
Packit Service f1eddf
	int count;
Packit ed3af9
Packit ed3af9
	if(flag) {
Packit ed3af9
		scd->curbit = 0;
Packit ed3af9
		scd->lastbit = 0;
Packit ed3af9
		scd->last_byte = 2;
Packit ed3af9
		scd->done = FALSE;
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if((scd->curbit + code_size) >= scd->lastbit) {
Packit ed3af9
		if(scd->done) {
Packit ed3af9
			if(scd->curbit >= scd->lastbit) {
Packit ed3af9
				/* Oh well */
Packit ed3af9
			}
Packit ed3af9
			return -1;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		scd->buf[0] = scd->buf[scd->last_byte - 2];
Packit ed3af9
		scd->buf[1] = scd->buf[scd->last_byte - 1];
Packit ed3af9
Packit ed3af9
		if((count = GetDataBlock(fd, &scd->buf[2], ZeroDataBlockP)) <= 0) {
Packit ed3af9
			scd->done = TRUE;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		scd->last_byte = 2 + count;
Packit ed3af9
		scd->curbit = (scd->curbit - scd->lastbit) + 16;
Packit ed3af9
		scd->lastbit = (2 + count) * 8;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if ((scd->curbit + code_size - 1) >= (CSD_BUF_SIZE * 8)) {
Packit ed3af9
		ret = -1;
Packit ed3af9
	} else {
Packit ed3af9
		ret = 0;
Packit ed3af9
		for (i = scd->curbit, j = 0; j < code_size; ++i, ++j) {
Packit ed3af9
			ret |= ((scd->buf[i / 8] & (1 << (i % 8))) != 0) << j;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	scd->curbit += code_size;
Packit ed3af9
Packit ed3af9
	return ret;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
GetCode(gdIOCtx *fd, CODE_STATIC_DATA *scd, int code_size, int flag, int *ZeroDataBlockP)
Packit ed3af9
{
Packit ed3af9
	int rv;
Packit ed3af9
Packit ed3af9
	rv = GetCode_(fd, scd, code_size,flag, ZeroDataBlockP);
Packit ed3af9
Packit ed3af9
	if(VERBOSE) {
Packit ed3af9
		printf("[GetCode(,%d,%d) returning %d]\n",code_size,flag,rv);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return rv;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
LWZReadByte_(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP)
Packit ed3af9
{
Packit ed3af9
	int code, incode, i;
Packit ed3af9
Packit ed3af9
	if(flag) {
Packit ed3af9
		sd->set_code_size = input_code_size;
Packit ed3af9
		sd->code_size = sd->set_code_size + 1;
Packit ed3af9
		sd->clear_code = 1 << sd->set_code_size;
Packit ed3af9
		sd->end_code = sd->clear_code + 1;
Packit ed3af9
		sd->max_code_size = 2 * sd->clear_code;
Packit ed3af9
		sd->max_code = sd->clear_code + 2;
Packit ed3af9
Packit ed3af9
		GetCode(fd, &sd->scd, 0, TRUE, ZeroDataBlockP);
Packit ed3af9
Packit ed3af9
		sd->fresh = TRUE;
Packit ed3af9
Packit ed3af9
		for(i = 0; i < sd->clear_code; ++i) {
Packit ed3af9
			sd->table[0][i] = 0;
Packit ed3af9
			sd->table[1][i] = i;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		for(; i < (1 << MAX_LWZ_BITS); ++i) {
Packit ed3af9
			sd->table[0][i] = sd->table[1][0] = 0;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		sd->sp = sd->stack;
Packit ed3af9
Packit ed3af9
		return 0;
Packit ed3af9
Packit ed3af9
	} else if(sd->fresh) {
Packit ed3af9
		sd->fresh = FALSE;
Packit ed3af9
Packit ed3af9
		do {
Packit ed3af9
			sd->firstcode = sd->oldcode =
Packit ed3af9
			                    GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
Packit ed3af9
		} while(sd->firstcode == sd->clear_code);
Packit ed3af9
Packit ed3af9
		return sd->firstcode;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if(sd->sp > sd->stack) {
Packit ed3af9
		return *--sd->sp;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	while((code = GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP)) >= 0) {
Packit ed3af9
		if(code == sd->clear_code) {
Packit ed3af9
			for(i = 0; i < sd->clear_code; ++i) {
Packit ed3af9
				sd->table[0][i] = 0;
Packit ed3af9
				sd->table[1][i] = i;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			for (; i < (1 << MAX_LWZ_BITS); ++i) {
Packit ed3af9
				sd->table[0][i] = sd->table[1][i] = 0;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			sd->code_size = sd->set_code_size + 1;
Packit ed3af9
			sd->max_code_size = 2 * sd->clear_code;
Packit ed3af9
			sd->max_code = sd->clear_code + 2;
Packit ed3af9
			sd->sp = sd->stack;
Packit ed3af9
			sd->firstcode = sd->oldcode =
Packit ed3af9
			                    GetCode(fd, &sd->scd, sd->code_size, FALSE, ZeroDataBlockP);
Packit ed3af9
Packit ed3af9
			return sd->firstcode;
Packit ed3af9
		} else if(code == sd->end_code) {
Packit ed3af9
			int count;
Packit ed3af9
			unsigned char buf[260];
Packit ed3af9
Packit ed3af9
			if(*ZeroDataBlockP) {
Packit ed3af9
				return -2;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			while((count = GetDataBlock(fd, buf, ZeroDataBlockP)) > 0);
Packit ed3af9
Packit ed3af9
			if(count != 0) {
Packit ed3af9
				return -2;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		incode = code;
Packit ed3af9
Packit ed3af9
		if(sd->sp == (sd->stack + STACK_SIZE)) {
Packit ed3af9
			/* Bad compressed data stream */
Packit ed3af9
			return -1;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(code >= sd->max_code) {
Packit ed3af9
			*sd->sp++ = sd->firstcode;
Packit ed3af9
			code = sd->oldcode;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		while(code >= sd->clear_code) {
Packit ed3af9
			if(sd->sp == (sd->stack + STACK_SIZE)) {
Packit ed3af9
				/* Bad compressed data stream */
Packit ed3af9
				return -1;
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			*sd->sp++ = sd->table[1][code];
Packit ed3af9
Packit ed3af9
			if(code == sd->table[0][code]) {
Packit ed3af9
				/* Oh well */
Packit ed3af9
			}
Packit ed3af9
Packit ed3af9
			code = sd->table[0][code];
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		*sd->sp++ = sd->firstcode = sd->table[1][code];
Packit ed3af9
Packit ed3af9
		if((code = sd->max_code) < (1 << MAX_LWZ_BITS)) {
Packit ed3af9
			sd->table[0][code] = sd->oldcode;
Packit ed3af9
			sd->table[1][code] = sd->firstcode;
Packit ed3af9
			++sd->max_code;
Packit ed3af9
Packit ed3af9
			if((sd->max_code >= sd->max_code_size) && (sd->max_code_size < (1<
Packit ed3af9
				sd->max_code_size *= 2;
Packit ed3af9
				++sd->code_size;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		sd->oldcode = incode;
Packit ed3af9
Packit ed3af9
		if(sd->sp > sd->stack) {
Packit ed3af9
			return *--sd->sp;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return code;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int
Packit ed3af9
LWZReadByte(gdIOCtx *fd, LZW_STATIC_DATA *sd, char flag, int input_code_size, int *ZeroDataBlockP)
Packit ed3af9
{
Packit ed3af9
	int rv;
Packit ed3af9
Packit ed3af9
	rv = LWZReadByte_(fd, sd, flag, input_code_size, ZeroDataBlockP);
Packit ed3af9
Packit ed3af9
	if(VERBOSE) {
Packit ed3af9
		printf("[LWZReadByte(,%d,%d) returning %d]\n",flag,input_code_size,rv);
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return rv;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static void
Packit ed3af9
ReadImage(gdImagePtr im, gdIOCtx *fd, int len, int height, unsigned char (*cmap)[256], int interlace, int *ZeroDataBlockP) /*1.4//, int ignore) */
Packit ed3af9
{
Packit ed3af9
	unsigned char c;
Packit ed3af9
	int xpos = 0, ypos = 0, pass = 0;
Packit ed3af9
	int v, i;
Packit ed3af9
	LZW_STATIC_DATA sd;
Packit ed3af9
Packit ed3af9
	/* Initialize the Compression routines */
Packit ed3af9
	if(!ReadOK(fd, &c, 1)) {
Packit ed3af9
		return;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if(c > MAX_LWZ_BITS) {
Packit ed3af9
		return;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* Stash the color map into the image */
Packit ed3af9
	for(i=0; (i < gdMaxColors); i++) {
Packit ed3af9
		im->red[i] = cmap[CM_RED][i];
Packit ed3af9
		im->green[i] = cmap[CM_GREEN][i];
Packit ed3af9
		im->blue[i] = cmap[CM_BLUE][i];
Packit ed3af9
		im->open[i] = 1;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* Many (perhaps most) of these colors will remain marked open. */
Packit ed3af9
	im->colorsTotal = gdMaxColors;
Packit ed3af9
	if(LWZReadByte(fd, &sd, TRUE, c, ZeroDataBlockP) < 0) {
Packit ed3af9
		return;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/*
Packit ed3af9
	**  If this is an "uninteresting picture" ignore it.
Packit ed3af9
	**  REMOVED For 1.4
Packit ed3af9
	*/
Packit ed3af9
	/*if (ignore) { */
Packit ed3af9
	/*        while (LWZReadByte(fd, &sd, FALSE, c) >= 0) */
Packit ed3af9
	/*                ; */
Packit ed3af9
	/*        return; */
Packit ed3af9
	/*} */
Packit ed3af9
Packit ed3af9
	while((v = LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP)) >= 0 ) {
Packit ed3af9
		if(v >= gdMaxColors) {
Packit ed3af9
			v = 0;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		/* This how we recognize which colors are actually used. */
Packit ed3af9
		if(im->open[v]) {
Packit ed3af9
			im->open[v] = 0;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		gdImageSetPixel(im, xpos, ypos, v);
Packit ed3af9
Packit ed3af9
		++xpos;
Packit ed3af9
		if(xpos == len) {
Packit ed3af9
			xpos = 0;
Packit ed3af9
			if(interlace) {
Packit ed3af9
				switch (pass) {
Packit ed3af9
				case 0:
Packit ed3af9
				case 1:
Packit ed3af9
					ypos += 8;
Packit ed3af9
					break;
Packit ed3af9
				case 2:
Packit ed3af9
					ypos += 4;
Packit ed3af9
					break;
Packit ed3af9
				case 3:
Packit ed3af9
					ypos += 2;
Packit ed3af9
					break;
Packit ed3af9
				}
Packit ed3af9
Packit ed3af9
				if(ypos >= height) {
Packit ed3af9
					++pass;
Packit ed3af9
					switch (pass) {
Packit ed3af9
					case 1:
Packit ed3af9
						ypos = 4;
Packit ed3af9
						break;
Packit ed3af9
					case 2:
Packit ed3af9
						ypos = 2;
Packit ed3af9
						break;
Packit ed3af9
					case 3:
Packit ed3af9
						ypos = 1;
Packit ed3af9
						break;
Packit ed3af9
					default:
Packit ed3af9
						goto fini;
Packit ed3af9
					}
Packit ed3af9
				}
Packit ed3af9
			} else {
Packit ed3af9
				++ypos;
Packit ed3af9
			}
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(ypos >= height) {
Packit ed3af9
			break;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
fini:
Packit ed3af9
	if(LWZReadByte(fd, &sd, FALSE, c, ZeroDataBlockP) >=0) {
Packit ed3af9
		/* Ignore extra */
Packit ed3af9
	}
Packit ed3af9
}