Blame src/gd_io_dp.c

Packit ed3af9
/*
Packit ed3af9
 * io_dp.c
Packit ed3af9
 *
Packit ed3af9
 * Implements the dynamic pointer interface.
Packit ed3af9
 *
Packit ed3af9
 * Based on GD.pm code by Lincoln Stein for interfacing to libgd.
Packit ed3af9
 * Added support for reading as well as support for 'tell' and 'seek'.
Packit ed3af9
 *
Packit ed3af9
 * As will all I/O modules, most functions are for local use only (called
Packit ed3af9
 * via function pointers in the I/O context).
Packit ed3af9
 *
Packit ed3af9
 * gdDPExtractData is the exception to this: it will return the pointer to
Packit ed3af9
 * the internal data, and reset the internal storage.
Packit ed3af9
 *
Packit ed3af9
 * Written/Modified 1999, Philip Warner.
Packit ed3af9
 */
Packit ed3af9
Packit ed3af9
#ifdef HAVE_CONFIG_H
Packit ed3af9
#	include "config.h"
Packit ed3af9
#endif
Packit ed3af9
Packit ed3af9
#include <math.h>
Packit ed3af9
#include <string.h>
Packit ed3af9
#include <stdlib.h>
Packit ed3af9
#include "gd.h"
Packit ed3af9
#include "gdhelpers.h"
Packit ed3af9
Packit ed3af9
#define TRUE	1
Packit ed3af9
#define FALSE	0
Packit ed3af9
Packit ed3af9
/* this is used for creating images in main memory */
Packit ed3af9
typedef struct dpStruct {
Packit ed3af9
	void *data;
Packit ed3af9
	int logicalSize;
Packit ed3af9
	int realSize;
Packit ed3af9
	int dataGood;
Packit ed3af9
	int pos;
Packit ed3af9
	int freeOK;
Packit ed3af9
}
Packit ed3af9
dynamicPtr;
Packit ed3af9
Packit ed3af9
typedef struct dpIOCtx {
Packit ed3af9
	gdIOCtx ctx;
Packit ed3af9
	dynamicPtr *dp;
Packit ed3af9
}
Packit ed3af9
dpIOCtx;
Packit ed3af9
Packit ed3af9
typedef struct dpIOCtx *dpIOCtxPtr;
Packit ed3af9
Packit ed3af9
/* these functions operate on in-memory dynamic pointers */
Packit ed3af9
static int allocDynamic(dynamicPtr *dp, int initialSize, void *data);
Packit ed3af9
static int appendDynamic(dynamicPtr *dp, const void *src, int size);
Packit ed3af9
static int gdReallocDynamic(dynamicPtr *dp, int required);
Packit ed3af9
static int trimDynamic(dynamicPtr *dp);
Packit ed3af9
static void gdFreeDynamicCtx(struct gdIOCtx *ctx);
Packit ed3af9
static dynamicPtr *newDynamic(int initialSize, void *data, int freeOKFlag);
Packit ed3af9
Packit ed3af9
static int dynamicPutbuf(struct gdIOCtx *, const void *, int);
Packit ed3af9
static void dynamicPutchar(struct gdIOCtx *, int a);
Packit ed3af9
Packit ed3af9
static int dynamicGetbuf(gdIOCtxPtr ctx, void *buf, int len);
Packit ed3af9
static int dynamicGetchar(gdIOCtxPtr ctx);
Packit ed3af9
Packit ed3af9
static int dynamicSeek(struct gdIOCtx *, const int);
Packit ed3af9
static long dynamicTell(struct gdIOCtx *);
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdNewDynamicCtx
Packit ed3af9
Packit ed3af9
	Return data as a dynamic pointer.
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdIOCtx *) gdNewDynamicCtx(int initialSize, void *data)
Packit ed3af9
{
Packit ed3af9
	/* 2.0.23: Phil Moore: 'return' keyword was missing! */
Packit ed3af9
	return gdNewDynamicCtxEx(initialSize, data, 1);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdNewDynamicCtxEx
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(gdIOCtx *) gdNewDynamicCtxEx(int initialSize, void *data, int freeOKFlag)
Packit ed3af9
{
Packit ed3af9
	dpIOCtx *ctx;
Packit ed3af9
	dynamicPtr *dp;
Packit ed3af9
Packit ed3af9
	ctx = (dpIOCtx *)gdMalloc(sizeof (dpIOCtx));
Packit ed3af9
	if(ctx == NULL) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	dp = newDynamic(initialSize, data, freeOKFlag);
Packit ed3af9
	if(!dp) {
Packit ed3af9
		gdFree (ctx);
Packit ed3af9
		return NULL;
Packit ed3af9
	};
Packit ed3af9
Packit ed3af9
	ctx->dp = dp;
Packit ed3af9
Packit ed3af9
	ctx->ctx.getC = dynamicGetchar;
Packit ed3af9
	ctx->ctx.putC = dynamicPutchar;
Packit ed3af9
Packit ed3af9
	ctx->ctx.getBuf = dynamicGetbuf;
Packit ed3af9
	ctx->ctx.putBuf = dynamicPutbuf;
Packit ed3af9
Packit ed3af9
	ctx->ctx.seek = dynamicSeek;
Packit ed3af9
	ctx->ctx.tell = dynamicTell;
Packit ed3af9
Packit ed3af9
	ctx->ctx.gd_free = gdFreeDynamicCtx;
Packit ed3af9
Packit ed3af9
	return (gdIOCtx *)ctx;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/*
Packit ed3af9
	Function: gdDPExtractData
Packit ed3af9
*/
Packit ed3af9
BGD_DECLARE(void *) gdDPExtractData (struct gdIOCtx *ctx, int *size)
Packit ed3af9
{
Packit ed3af9
	dynamicPtr *dp;
Packit ed3af9
	dpIOCtx *dctx;
Packit ed3af9
	void *data;
Packit ed3af9
Packit ed3af9
	dctx = (dpIOCtx *)ctx;
Packit ed3af9
	dp = dctx->dp;
Packit ed3af9
Packit ed3af9
	/* clean up the data block and return it */
Packit ed3af9
	if(dp->dataGood) {
Packit ed3af9
		trimDynamic(dp);
Packit ed3af9
		*size = dp->logicalSize;
Packit ed3af9
		data = dp->data;
Packit ed3af9
	} else {
Packit ed3af9
		*size = 0;
Packit ed3af9
		data = NULL;
Packit ed3af9
		/* 2.0.21: never free memory we don't own */
Packit ed3af9
		if((dp->data != NULL) && (dp->freeOK)) {
Packit ed3af9
			gdFree(dp->data);
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	dp->data = NULL;
Packit ed3af9
	dp->realSize = 0;
Packit ed3af9
	dp->logicalSize = 0;
Packit ed3af9
Packit ed3af9
	return data;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static void gdFreeDynamicCtx(struct gdIOCtx *ctx)
Packit ed3af9
{
Packit ed3af9
	dynamicPtr *dp;
Packit ed3af9
	dpIOCtx *dctx;
Packit ed3af9
Packit ed3af9
	dctx = (dpIOCtx *)ctx;
Packit ed3af9
	dp = dctx->dp;
Packit ed3af9
Packit ed3af9
	gdFree(ctx);
Packit ed3af9
Packit ed3af9
	/* clean up the data block and return it */
Packit ed3af9
	/* 2.0.21: never free memory we don't own */
Packit ed3af9
	if((dp->data != NULL) && (dp->freeOK)) {
Packit ed3af9
		gdFree(dp->data);
Packit ed3af9
		dp->data = NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	dp->realSize = 0;
Packit ed3af9
	dp->logicalSize = 0;
Packit ed3af9
Packit ed3af9
	gdFree(dp);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static long dynamicTell(struct gdIOCtx *ctx)
Packit ed3af9
{
Packit ed3af9
	dpIOCtx *dctx;
Packit ed3af9
Packit ed3af9
	dctx = (dpIOCtx *)ctx;
Packit ed3af9
	return (dctx->dp->pos);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int dynamicSeek(struct gdIOCtx *ctx, const int pos)
Packit ed3af9
{
Packit ed3af9
	int bytesNeeded;
Packit ed3af9
	dynamicPtr *dp;
Packit ed3af9
	dpIOCtx *dctx;
Packit ed3af9
Packit ed3af9
	if (pos < 0) {
Packit ed3af9
		return FALSE;
Packit ed3af9
	}
Packit ed3af9
	dctx = (dpIOCtx *)ctx;
Packit ed3af9
	dp = dctx->dp;
Packit ed3af9
Packit ed3af9
	if(!dp->dataGood) {
Packit ed3af9
		return FALSE;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	bytesNeeded = pos;
Packit ed3af9
	if(bytesNeeded > dp->realSize) {
Packit ed3af9
		/* 2.0.21 */
Packit ed3af9
		if(!dp->freeOK) {
Packit ed3af9
			return FALSE;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(overflow2(dp->realSize, 2)) {
Packit ed3af9
			return FALSE;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(!gdReallocDynamic(dp, dp->realSize * 2)) {
Packit ed3af9
			dp->dataGood = FALSE;
Packit ed3af9
			return FALSE;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* if we get here, we can be sure that we have enough bytes
Packit ed3af9
	 * to copy safely */
Packit ed3af9
Packit ed3af9
	/* Extend the logical size if we seek beyond EOF. */
Packit ed3af9
	if(pos > dp->logicalSize) {
Packit ed3af9
		dp->logicalSize = pos;
Packit ed3af9
	};
Packit ed3af9
Packit ed3af9
	dp->pos = pos;
Packit ed3af9
Packit ed3af9
	return TRUE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* return data as a dynamic pointer */
Packit ed3af9
static dynamicPtr *newDynamic(int initialSize, void *data, int freeOKFlag)
Packit ed3af9
{
Packit ed3af9
	dynamicPtr *dp;
Packit ed3af9
Packit ed3af9
	dp = (dynamicPtr *) gdMalloc(sizeof (dynamicPtr));
Packit ed3af9
	if(dp == NULL) {
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if(!allocDynamic(dp, initialSize, data)) {
Packit ed3af9
		gdFree(dp);
Packit ed3af9
		return NULL;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	dp->pos = 0;
Packit ed3af9
	dp->freeOK = freeOKFlag;
Packit ed3af9
Packit ed3af9
	return dp;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int dynamicPutbuf(struct gdIOCtx *ctx, const void *buf, int size)
Packit ed3af9
{
Packit ed3af9
	dpIOCtx *dctx;
Packit ed3af9
	dctx = (dpIOCtx *)ctx;
Packit ed3af9
Packit ed3af9
	appendDynamic(dctx->dp, buf, size);
Packit ed3af9
Packit ed3af9
	if(dctx->dp->dataGood) {
Packit ed3af9
		return size;
Packit ed3af9
	} else {
Packit ed3af9
		return -1;
Packit ed3af9
	};
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static void dynamicPutchar(struct gdIOCtx *ctx, int a)
Packit ed3af9
{
Packit ed3af9
	unsigned char b;
Packit ed3af9
	dpIOCtxPtr dctx;
Packit ed3af9
Packit ed3af9
	b = a;
Packit ed3af9
	dctx = (dpIOCtxPtr) ctx;
Packit ed3af9
Packit ed3af9
	appendDynamic(dctx->dp, &b, 1);
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* returns the number of bytes actually read; 0 on EOF and error */
Packit ed3af9
static int dynamicGetbuf(gdIOCtxPtr ctx, void *buf, int len)
Packit ed3af9
{
Packit ed3af9
	int rlen, remain;
Packit ed3af9
	dpIOCtxPtr dctx;
Packit ed3af9
	dynamicPtr *dp;
Packit ed3af9
Packit ed3af9
	dctx = (dpIOCtxPtr) ctx;
Packit ed3af9
	dp = dctx->dp;
Packit ed3af9
Packit ed3af9
	if (dp->pos < 0 || dp->pos >= dp->realSize) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	remain = dp->logicalSize - dp->pos;
Packit ed3af9
	if(remain >= len) {
Packit ed3af9
		rlen = len;
Packit ed3af9
	} else {
Packit ed3af9
		if(remain <= 0) {
Packit ed3af9
			return 0;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		rlen = remain;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (dp->pos + rlen > dp->realSize) {
Packit ed3af9
		rlen = dp->realSize - dp->pos;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if (rlen < 0) {
Packit ed3af9
		return 0;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	memcpy(buf, (void *) ((char *)dp->data + dp->pos), rlen);
Packit ed3af9
	dp->pos += rlen;
Packit ed3af9
Packit ed3af9
	return rlen;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
static int dynamicGetchar(gdIOCtxPtr ctx)
Packit ed3af9
{
Packit ed3af9
	unsigned char b;
Packit ed3af9
	int rv;
Packit ed3af9
Packit ed3af9
	rv = dynamicGetbuf(ctx, &b, 1);
Packit ed3af9
Packit ed3af9
	if(rv != 1) {
Packit ed3af9
		return EOF;
Packit ed3af9
	} else {
Packit ed3af9
		return b; /* (b & 0xff); */
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/**********************************************************************
Packit ed3af9
 * InitDynamic - Return a dynamically resizable void*
Packit ed3af9
 **********************************************************************/
Packit ed3af9
static int allocDynamic(dynamicPtr *dp, int initialSize, void *data)
Packit ed3af9
{
Packit ed3af9
	if(data == NULL) {
Packit ed3af9
		dp->logicalSize = 0;
Packit ed3af9
		dp->dataGood = FALSE;
Packit ed3af9
		dp->data = gdMalloc(initialSize);
Packit ed3af9
	} else {
Packit ed3af9
		dp->logicalSize = initialSize;
Packit ed3af9
		dp->dataGood = TRUE;
Packit ed3af9
		dp->data = data;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	if(dp->data != NULL) {
Packit ed3af9
		dp->realSize = initialSize;
Packit ed3af9
		dp->dataGood = TRUE;
Packit ed3af9
		dp->pos = 0;
Packit ed3af9
		return TRUE;
Packit ed3af9
	} else {
Packit ed3af9
		dp->realSize = 0;
Packit ed3af9
		return FALSE;
Packit ed3af9
	}
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* append bytes to the end of a dynamic pointer */
Packit ed3af9
static int appendDynamic(dynamicPtr * dp, const void *src, int size)
Packit ed3af9
{
Packit ed3af9
	int bytesNeeded;
Packit ed3af9
	char *tmp;
Packit ed3af9
Packit ed3af9
	if(!dp->dataGood) {
Packit ed3af9
		return FALSE;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* bytesNeeded = dp->logicalSize + size; */
Packit ed3af9
	bytesNeeded = dp->pos + size;
Packit ed3af9
Packit ed3af9
	if(bytesNeeded > dp->realSize) {
Packit ed3af9
		/* 2.0.21 */
Packit ed3af9
		if(!dp->freeOK) {
Packit ed3af9
			return FALSE;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(overflow2(dp->realSize, 2)) {
Packit ed3af9
			return FALSE;
Packit ed3af9
		}
Packit ed3af9
Packit ed3af9
		if(!gdReallocDynamic(dp, bytesNeeded * 2)) {
Packit ed3af9
			dp->dataGood = FALSE;
Packit ed3af9
			return FALSE;
Packit ed3af9
		}
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* if we get here, we can be sure that we have enough bytes
Packit ed3af9
	 * to copy safely */
Packit ed3af9
Packit ed3af9
	/*printf("Mem OK Size: %d, Pos: %d\n", dp->realSize, dp->pos); */
Packit ed3af9
Packit ed3af9
	tmp = (char *)dp->data;
Packit ed3af9
	memcpy ((void *)(tmp + (dp->pos)), src, size);
Packit ed3af9
	dp->pos += size;
Packit ed3af9
Packit ed3af9
	if(dp->pos > dp->logicalSize) {
Packit ed3af9
		dp->logicalSize = dp->pos;
Packit ed3af9
	};
Packit ed3af9
Packit ed3af9
	return TRUE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* grow (or shrink) dynamic pointer */
Packit ed3af9
static int gdReallocDynamic(dynamicPtr *dp, int required)
Packit ed3af9
{
Packit ed3af9
	void *newPtr;
Packit ed3af9
Packit ed3af9
	/* First try gdRealloc().  If that doesn't work, make a new
Packit ed3af9
	 * memory block and copy. */
Packit ed3af9
	if((newPtr = gdRealloc(dp->data, required))) {
Packit ed3af9
		dp->realSize = required;
Packit ed3af9
		dp->data = newPtr;
Packit ed3af9
		return TRUE;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* create a new pointer */
Packit ed3af9
	newPtr = gdMalloc(required);
Packit ed3af9
	if(!newPtr) {
Packit ed3af9
		dp->dataGood = FALSE;
Packit ed3af9
		return FALSE;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	/* copy the old data into it */
Packit ed3af9
	memcpy(newPtr, dp->data, dp->logicalSize);
Packit ed3af9
	gdFree(dp->data);
Packit ed3af9
	dp->data = newPtr;
Packit ed3af9
Packit ed3af9
	dp->realSize = required;
Packit ed3af9
	return TRUE;
Packit ed3af9
}
Packit ed3af9
Packit ed3af9
/* trim pointer so that its real and logical sizes match */
Packit ed3af9
static int trimDynamic(dynamicPtr *dp)
Packit ed3af9
{
Packit ed3af9
	/* 2.0.21: we don't reallocate memory we don't own */
Packit ed3af9
	if(!dp->freeOK) {
Packit ed3af9
		return TRUE;
Packit ed3af9
	}
Packit ed3af9
Packit ed3af9
	return gdReallocDynamic(dp, dp->logicalSize);
Packit ed3af9
}