/*
 *  TEX Device Driver  ver 2.02-
 *  copyright(c) 1988, 1989 by TSG, 1990-93 by SHIMA
 *  1990 changed by M.Watanabe
 *  1991 changed by hideki
 *  1991 changed by T.Minagawa
 *
 *  flifont.c : module to handle FLI font library
 *
 *  Feb.  7, 1993 : 2nd edition   by H.Yoshizaki
 *  Jul.  4, 1993 : 3rd edition   by H.Yoshizaki
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef  UNIX
#include <unistd.h>
#endif

#ifdef MSVC
#pragma warning( disable : 4244 4018 4102 4761 )
#endif

#include "flifont.h"
#include "dd.h"
#include "err.h"

#ifndef	DEBUG
#define	DEBUG	0
#endif

#define	get1()	getc(fp)

void Free(void *);

/* loadpk.c */
FILE *fopenf(char *, char *);

void *marea(unsigned int);

#if FLIVER1
static short ver;
#endif

static FILE *fp;
static struct HDR *fli_hdr_root;

static unsigned short get2(void)
{
	union {
		unsigned short tmpshort;
		unsigned char tmpchar[2];
	} tmp;

#if	FLIVER1
	if (ver == 1) {
		tmp.tmpchar[0] = get1();
		tmp.tmpchar[1] = get1();
	} else {
#endif
		tmp.tmpchar[1] = get1();
		tmp.tmpchar[0] = get1();
#if	FLIVER1
	}
#endif
	return tmp.tmpshort;
}

static unsigned long get4(void)
{
	union {
		unsigned long tmplong;
		unsigned char tmpchar[4];
	} tmp;

#if	FLIVER1
	if (ver == 1) {
		tmp.tmpchar[0] = get1();
		tmp.tmpchar[1] = get1();
		tmp.tmpchar[2] = get1();
		tmp.tmpchar[3] = get1();
	} else {
#endif
		tmp.tmpchar[3] = get1();
		tmp.tmpchar[2] = get1();
		tmp.tmpchar[1] = get1();
		tmp.tmpchar[0] = get1();
#if	FLIVER1
	}
#endif
	return tmp.tmplong;
}

static void *alloc(int size)
{
	void *tmp;
	tmp = marea(size);
	if (tmp) memset(tmp, '\0', size);
	else error(NO_MEMORY, "near heap for FLI");
	return tmp;
}

static struct HDR *read_fli(char *name)
{
	struct HDR *hdr;
	struct SIZ **snext;
	char buf[4] = "";
	short h_numsiz;

	hdr = alloc(sizeof(struct HDR) + strlen(name));
	strcpy(hdr -> name, name);
	if ((fp = fopenf(name, "rb")) == NULL) return hdr;
	fread(buf, 4, 1, fp);
#if	FLIVER1
	hdr -> version = ver = get1();
	if (strlcmp(buf, "FLIB") == 0 && (ver == 1 || ver == 2)) {
#else
	if (strlcmp(buf, "FLIB") == 0 && get1() == 2) {
#endif
		(void)get1();
		(void)get2();
		h_numsiz = get2();
		(void)get2();
		fseek(fp, get2(), SEEK_CUR);
		snext = &(hdr -> size);
		while(h_numsiz--) {
			struct SIZ *siz;
			struct FNT **fnext;
			short s_numfnt;

			*snext = siz = alloc(sizeof(struct SIZ));
			snext = &(siz -> next);
			get2();
#if	FLIVER1
			if (ver == 1) {
				siz -> dpi = get2();
				s_numfnt = get2();
			} else {
#endif
				s_numfnt = get2();
				siz -> dpi = (get4() * 5 + 0x8000L) / 0x10000L;
#if	FLIVER1
			}
#endif
			fnext = &(siz -> font);
			while (s_numfnt--) {
				struct FNT *fnt;
				long fontlen;
				long fontpos;
				char namelen;

				fontlen = get4();
				fontpos = get4();
				namelen = get1();
				*fnext = fnt = alloc(sizeof(struct FNT) + namelen);
				fnext = &(fnt -> next);
				fnt -> fontlen = fontlen;
				fnt -> fontpos = fontpos;
				fread(fnt -> name, namelen, 1, fp);
			}
			*fnext = NULL;
		}
		*snext = NULL;
	}
	fclose(fp);
	return hdr;
}

struct FNT *search_fli(char *filename, char *fontname, int dpi)
{
	struct HDR **phdr, *hdr;
	struct SIZ *size;
	struct FNT *font;

	phdr = &fli_hdr_root;
	while (1) {
		if (*phdr == NULL) *phdr = read_fli(filename);
		hdr = *phdr;
		if (strcmp(filename, hdr -> name) == 0) {
			size = hdr -> size;
			while (size) {
				if (abs(dpi - size -> dpi) <= 1) {
					font = size -> font;
					while (font) {
#if	FLIVER1
						if (hdr -> version == 1) {
							if (strncmp(fontname, font -> name, 8) == 0)
								return font;
						} else {
#endif
							if (strcmp(fontname, font -> name) == 0)
								return font;
#if	FLIVER1
						}
#endif
						font = font -> next;
					}
				}
				size = size -> next;
			}
			return NULL;
		}
		phdr = &(hdr -> next);
	}
}

void free_fli(void)
{
	struct HDR *hdr, *ohdr;
	struct SIZ *size, *osize;
	struct FNT *font, *ofont;

	hdr = fli_hdr_root;
	while (hdr) {
#if	DEBUG
		printf("Header : %s\n", hdr -> name);
#endif
		size = hdr -> size;
		while (size) {
#if	DEBUG
			printf("  Size : %d\n", size -> dpi);
#endif
			font = size -> font;
			while (font) {
#if	DEBUG
				printf("    Font : %04lX %08lX %s\n", 
					font -> fontlen, font -> fontpos, font -> name);
#endif
				font = (ofont = font) -> next;
				Free(ofont);
			}
			size = (osize = size) -> next;
			Free(osize);
		}
		hdr = (ohdr = hdr) -> next;
		Free(ohdr);
	}
	fli_hdr_root = NULL;
}
