/**
 * INCLUDES
 **/
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>

/**
 * TYPEDEFS
 **/
typedef unsigned long ulong;


/**
 * DEFINES
 **/
#define ERR_MSG_BUFSIZE 120
#define ERR_HEADER "readfont:"
#define MSG_OUT_OF_MEM "readfont:Out of memory"
#define MSG_CANT_GET_SIZE "readfont:Can't get size"
#define MSG_CANT_OPEN_FILE "readfont:Can't open file"
#define MSG_FONT_UNPACK_ERROR "readfont:Error unpacking font"


#ifdef VERBOSE
/**
 * GLOBALS
 **/
UBYTE ErrMsgBuf[ERR_MSG_BUFSIZE];
#endif

/**
 * PROTOTYPES
 **/
void freefont(char *fbuf);
int readfont(char *filename, char **pfbuf, int *pfbuflen);
static long get_size(BPTR filepointer);
static ulong convert_ulong(ulong l);


/****/
/** MAIN **/
/****/
#ifdef TESTREADFONT
//int main(int ac, char *av[])
//{
//	char fnamedef[11] = "Dragonwick";
//	char *filename;
//	char *fbuf;
//	long fbuflen;
//
//	if (ac == 1)
//		filename = fnamedef;
//	else
//		filename = av[1];
//
//	if (readfont(filename, &fbuf, &fbuflen) < 0)
//	{
//		printf("%s\n", ErrMsgBuf);
//		return 10;
//	}
//
//	printf("fbuflen = %ld\n", fbuflen);
//
//	freefont(fbuf);
//	return 0;
//}
#endif

/****/
/** Frees the memory allocated to store a font **/
/****/
void freefont(char *fbuf)
{
	if (fbuf) FreeVec(fbuf);
}


/****/
/** Reads a font into memory **
/****/
int readfont(char *filename, char **pfbuf, int *pfbuflen)
{
	BPTR fp;
	long fsize;
	long ch;
	int rc = 0;
	ulong chunklen;
	char *bufptr;
	char *fbuf = NULL;
	int fbuflen = 0;

	if (fp = Open(filename, MODE_OLDFILE))
	{
		if ((fsize = get_size(fp)) > 0)
		{
			if (fbuf = (char *)AllocVec(fsize, MEMF_PUBLIC))
			{
				/**
				 * Font is packed if first character is 0x80
				 **/
				ch = FGetC(fp);
				if (ch == 0x80)
				{
					/**
					 * Font is packed
					 **/
					bufptr = fbuf;
					ch = FGetC(fp);
					while (ch != 0x03)
					{
						if (FRead(fp, &chunklen, sizeof(ulong), 1) != 1)
							break;

						chunklen = convert_ulong(chunklen);

						if (FRead(fp, bufptr, chunklen, 1) != 1)
							break;

						bufptr += chunklen;


/* TetiSoft: Ensure that a missing EOF marker (0x80 0x03) is ok */
/*
						if (FGetC(fp) != 0x80)
							break;
*/
						ch = FGetC(fp);
						if (ch == -1)
						{
							ch = 0x03;
							break;
						}
						if (ch != 0x80)
						{
							ch = 0x00;
							break;
						}


						ch = FGetC(fp);
					}

					if (ch != 0x03)
					{
						rc = -1;
#ifdef VERBOSE
						strcpy(ErrMsgBuf, MSG_FONT_UNPACK_ERROR);
#endif
					}
					else
						fbuflen = bufptr - fbuf;
				}
				else
				{
					/**
					 * Font is not packed
					 **/
					UnGetC(fp, -1);		/* push back the last character read */
					SetIoErr(0L);
					if (FRead(fp, fbuf, fsize, 1) != 1)
					{
						rc = -1;
#ifdef VERBOSE
						Fault(IoErr(), ERR_HEADER, ErrMsgBuf, ERR_MSG_BUFSIZE);
#endif
					}
					else
						fbuflen = fsize;
				}
			}
			else
			{
				rc = -1;
#ifdef VERBOSE
				strcpy(ErrMsgBuf, MSG_OUT_OF_MEM);
#endif
			}
		}
		else
		{
			rc = -1;
#ifdef VERBOSE
			strcpy(ErrMsgBuf, MSG_CANT_GET_SIZE);
#endif
		}
		Close(fp);
	}
	else
	{
		rc = -1;
#ifdef VERBOSE
		strcpy(ErrMsgBuf, MSG_CANT_OPEN_FILE);
#endif
	}

	if ((rc == -1) && (fbuf))
	{
		FreeVec(fbuf);
		fbuf = NULL;
	}

	*pfbuf = fbuf;
	*pfbuflen = fbuflen;

	return rc;
}


/****/
/** Returns the size of a file **/
/****/
static long get_size(BPTR filepointer)
{
/* TetiSoft: SAS/C manual chapter 11 page 172: __aligned may not work in a shared library */
/*
	struct FileInfoBlock __aligned fib;
	if (!(ExamineFH(filepointer, &fib)))
		return -1;
	return(fib.fib_Size);
*/
	struct FileInfoBlock *fib;
	long rc;
	fib = AllocDosObject(DOS_FIB, NULL);
	if(!fib)
		return -1;
	if (!(ExamineFH(filepointer, fib)))
	{
		FreeDosObject(DOS_FIB, fib);
		return -1;
	}
	rc = fib->fib_Size;
	FreeDosObject(DOS_FIB, fib);
	return rc;
}


/****/
/** Converts a ULONG between little and big endian **/
/****/
static ulong convert_ulong(ulong l)
{
	ulong t;

	t=(l>>16)|(l<<16);
	t=((t<<8)&0xff00ff00)|((t>>8)&0x00ff00ff);
	return(t);
}
