/*
*               TeX Device Driver DVIOUT, DVIPRT で
*               MS Windows の TrueType font を使う
*
*                            ttfont.c
*
*     "本プログラムは、T.Minagawa 氏の vfont.c, vdata.c, vraster.c,
*      Naochan! 氏の jgfont.c 等を参考にしており，またこれらのプログ
*      ラムに全面的に依存しています。
*      TrueType font の詳細については、"TrueType font specifications",
*      "tffname.c" (いずれも (c) Microsoft Corporation.) を参考にして
*      います。
*
*      14 Nov. 1993  by I.Matsuda
*      29 May  1994  Supported CM-TT font  by I.Matsuda
*       2 June 1994  Bug fixed for ascgrp.ttf  by I.Matsuda
*       9 June 1994  Supported new CM-TT font  by I.Matsuda
*      17 Nov. 1994  Bug fixed by I.Matsuda
*	   20 Jul. 2001  Font embedding by T.Oshima
*/

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

#ifdef  UNIX
#include <unistd.h>
#else
#ifdef MSVC
#include "msvcdir.h"
#else
#include <dir.h>
#endif
#include <io.h>
# ifdef	GCC1
#include <djgppstd.h>
# else
#ifdef MSVC
#include <malloc.h>
#else
#include <alloc.h>
#endif
#endif
#endif

#include "dd.h"
#include "err.h"
#include "buffer.h"
#include "vfont.h"
#include "vraster.h"
#include "ttfont.h"
#include "inter.h"

static TT_INFO *TTinfo[MAX_VFONT];
static CMTT_INFO far *cmtt_ptr;
static GLYPH glyph;
static int basis[3][15];				/* スプラインの基底 */
static BOOL f_more_glyph = FALSE;		/* composite glyph */

/* vfont.c */
extern V_FONT *vfont[MAX_VFONT];

int get_ttinfo(int, int);
uchar *get_cmttinfo(int, int);
void ttf_metrics(FONT_INFO *, int, PREAMBLE *);
int seek_to_tt_data(VPARA_TBL *);
int get_tt_glyph(VPARA_TBL *);
int get_tt_xy(LOCATE *);

static ulong get_glyph_offset(int, uint);
static long load_composite_glyph(VPARA_TBL *);
static int get_tt_list(int);
static double read_F2Dot14(int);
static long tt_seek(int , long , int);
static ulong read_n_byte(int , int);

/* vfont.c */
int open_vfont(int, char *, char *, char *, char *);

/* vdata.c */
extern short bufx[VF_BUF_SIZE];	/* データ先読みバッファ */

/* buffer.c */
void *marea(unsigned int);

/* getfont.c */
long tfm_width(BUFFER *, int);

/* loadpk.c */
int openf(char *, int);

/* sptopxl.asm  */
PIXEL sptopixel(SCALED_PT);
PIXEL vtopixel(SCALED_PT);

/* mult20.asm */
SCALED_PT mult20(SCALED_PT, SCALED_PT);

/* epsbox.c */
void putint(int, FILE *);

/* winjtt.c */
int TransEuroTTCode(int, int);

#ifdef	USE_ETF
#define	ETF_PACK 1
/* prtinit.c */
int GetAddMemory(char *, char *, int);

/* virtual.c */
BUFFER *MakeLocalFontList(FONT_INFO *, uchar *);

/* tabctrl.c */
BOOL ArrangeETFFont(ETF_INFO *, short int *, int, int, ETF_IMAGE *);

/* getfont.c */
JFM_DATA *jfm_read(FONT_INFO *font, int char_code);

/* load_pk.c */
BUFFER *load_pk(char *, char *);

/* winjtt.c */
char *check_ftt(char *);

/* mwndproc.c */
void EnableETFInfo(BOOL);

#define	GetInt(x)	(*(int*)(x))
// #define	GetShort(x)	(*(short int*)(x))
#define	ETF_BLOCK		0x1000
#define	ETF_COMPOSITE	0x40000000

static unsigned char *etf_font;		/* current ETF font */
static FONT_INDEX	*etf_idx;		/* current ETF_INDEX */
static int	etf_max_idx;			/* current max_index */
static int	*etf_map;				/* current ETF_MAP */
static int  etf_max_map;			/* current max_map */
static unsigned char *etf_glyph;	/* current GLYPH */
static int	etf_size;				/* size of ETF font */
static int	etf_map_top;
static int	etf_map_end;
static int	etf_jmap_top;
static int	etf_jmap_end;

BOOL f_make_etf;
BOOL f_make_pketf;
BOOL f_make_vfetf;
BOOL f_make_mapetf;
BOOL f_make_jttetf;
BOOL f_make_imgetf;
BOOL f_make_wjtetf;
BOOL f_use_etf = TRUE;
char *f_make_dpi;

static ETF_INFO *etf_info;
static int	etf_pt;
static int	etf_end;
static int	etf_error;
static int  extra;
static int etf_version;
static ETF_IMAGE etf_img;

#define	EXCEPTION	(1<<31)
#endif


/*************************************************************
*	get_ttinfo
*	*.tti のヘッダ情報を取得する
**************************************************************/
int get_ttinfo(int font_no, int fh)
{
	TTinfo[font_no] = (TT_INFO *)marea(sizeof(TT_INFO));
	tt_seek(fh, 0, SEEK_SET);
	TTinfo[font_no]->CodeTable	 = read_n_byte(fh, 2);
	TTinfo[font_no]->MaxJIS		 = read_n_byte(fh, 2);
	TTinfo[font_no]->unitsPerEm	 = read_n_byte(fh, 2);
	TTinfo[font_no]->xMin		 = (short int)read_n_byte(fh, 2);
	TTinfo[font_no]->yMin		 = (short int)read_n_byte(fh, 2);
	TTinfo[font_no]->maxPoints	 = read_n_byte(fh, 2);
	TTinfo[font_no]->maxContours = read_n_byte(fh, 2);
	TTinfo[font_no]->IndexBase	 = read_n_byte(fh, 4);
	TTinfo[font_no]->GlyphBase	 = read_n_byte(fh, 4);
	return (TRUE);
}

/*************************************************
*	Get glyph index of TrueType font of format 4
**************************************************/
static int GetGF4(int fh, int ch)
{
	int j, segment, dDelta, idRangeBase, R_offset, Start, Index;
	int *base = (int *)common_work;

	segment = -1;
	tt_seek(fh, cmtt_ptr->FirstCode, SEEK_SET);
	for(j = 0; j < cmtt_ptr->EntryCount; j++)
		base[j] = (uint)read_n_byte(fh, 2);		/* endCount */
	tt_seek(fh, 2, SEEK_CUR);
	for(j = 0; j < cmtt_ptr->EntryCount; j++){
		Start = (uint)read_n_byte(fh, 2);
		if(ch <= base[j] && ch >= Start){
			segment = j;
			break;
		}
	}
	if(segment < 0)
		Index = 0;
	else{
		tt_seek(fh, 2*(cmtt_ptr->EntryCount-1), SEEK_CUR);
		dDelta = (uint)read_n_byte(fh, 2);		/* get idDelta */
		tt_seek(fh, 2*(cmtt_ptr->EntryCount-segment-1), SEEK_CUR);
		idRangeBase = (uint)read_n_byte(fh, 0);
		tt_seek(fh, 2*j, SEEK_CUR);
		R_offset = (uint)read_n_byte(fh, 2);	/* idRangeOffset */
		if(!R_offset){
			Index = (ch + dDelta) & 0xffff;
		}else{
			Index = (R_offset/2 + ch - Start) & 0xffff;
			tt_seek(fh, idRangeBase + (segment+Index) * 2, SEEK_SET);
			Index = ((uint)read_n_byte(fh, 2)+dDelta)&0xffff;
		}
	}
	return Index;
}

/*************************************************************
*	get_cmttinfo
*	欧文 TT font のヘッダ情報を取得する
**************************************************************/
uchar *get_cmttinfo(int fh, int mode)
{
	int i, j, item = 0;
	BUFFER *p, *q;
	uint numOffsets, numTables, length;
	ulong tag, offset, offset2, offset3;
	static CMTT_INFO cmtt_info;

	static struct TTID {
		char 	*name;
				short int type;
	} ttid[] = {
		"BaKoMa", 		0,
		"Monotype", 	0x80,
		"Microsoft", 	0x80,
		"Impress", 		0x83
	};

	tt_seek(fh, 4, SEEK_SET);
	if ((numOffsets = read_n_byte(fh, 2)) > 100)
		return (NULL);
	lseek(fh, 12, SEEK_SET);
	read(fh, tmp_buf, numOffsets << 4);
	p = (BUFFER *)tmp_buf;
	q = NULL;
	cmtt_info.f_type = mode;
	if(mode <= 256)
		cmtt_info.f_type--;

	for (i = 0; i < numOffsets || q != NULL; i++) {
		if(i >= numOffsets){
			p = q;
			q = NULL;
		}
		tag = get_long(p);
		move_ptr(p, 4);
		offset = get_long(p);
		move_ptr(p, 4);
		switch (tag)
		{
			case (tag_FontHeader):
				tt_seek(fh, offset + 18, SEEK_SET);
				cmtt_info.unitsPerEm = read_n_byte(fh, 2);
				tt_seek(fh, 30, SEEK_CUR);
				cmtt_info.indexToLocFormat = read_n_byte(fh, 2);
				item |= 0x01;
				break;

			case (tag_HoriHeader):
				tt_seek(fh, offset + 34, SEEK_SET);
				cmtt_info.numOfHMetrics = read_n_byte(fh, 2);
				item |= 0x02;
				break;

			case (tag_HorizontalMetrics):
				cmtt_info.HmtxBase = offset;
				item |= 0x04;
				break;

			case (tag_IndexToLoc):
				cmtt_info.IndexBase = offset;
				item |= 0x08;
				break;

			case (tag_GlyphData):
				cmtt_info.GlyphBase = offset;
				item |= 0x10;
				break;

			case (tag_CharToIndexMap):
				if(cmtt_info.f_type < 0){
					if(q != NULL){
						q = NULL;
						break;
					}
					q = p - 16;
					break;
				}
				tt_seek(fh, offset + 2, SEEK_SET);
				numTables = read_n_byte(fh, 2);
				cmtt_info.CmapBase0 = 0;
				for (j = 0; j < numTables; j++) {
					tt_seek(fh, offset + 8 + (j << 3), SEEK_SET);
					offset2 = read_n_byte(fh, 4);
					tt_seek(fh, offset + offset2, SEEK_SET);
					cmtt_info.C2IndexFormat = (uint)read_n_byte(fh, 2);
					if (cmtt_info.C2IndexFormat == 0) {
						cmtt_info.CmapBase0 = offset + offset2 + 6;
						item |= 0x20;
						if(cmtt_info.f_type < 256 && (cmtt_info.f_type & 1))
													/* not BaKoMa */
							break;
					}else if(cmtt_info.C2IndexFormat == 4 
					  && (cmtt_info.f_type >= 256 || !(cmtt_info.f_type & 1))){
													/* BaKoMa */
						cmtt_info.CmapBase = offset + offset2 + 6;
						tt_seek(fh, 4, SEEK_CUR);
						cmtt_info.EntryCount = (uint)read_n_byte(fh, 2)/2;
						tt_seek(fh, 6, SEEK_CUR);
						cmtt_info.FirstCode = (uint)read_n_byte(fh, 0);
						item |= 0x20;
						break;
					}
					if (cmtt_info.C2IndexFormat == 6) {
						tt_seek(fh, 4, SEEK_CUR);
						cmtt_info.FirstCode = (uint)read_n_byte(fh, 2);
						cmtt_info.EntryCount = (uint)read_n_byte(fh, 2);
						cmtt_info.CmapBase = offset + offset2 + 10;
						item |= 0x20;
						break;
					}
				}
				q = NULL;
				break;

			case(tag_NamingTable):
				item |= 0x40;
				if(cmtt_info.f_type >= 0)
					break;
				tt_seek(fh, offset + 2, SEEK_SET);
				numTables = read_n_byte(fh, 2);
				offset2 = read_n_byte(fh, 2);
				offset3 = -1;
				for (i = -1, j = 0; j < numTables; j++) {
					tt_seek(fh, 6, SEEK_CUR);
					if(!read_n_byte(fh, 2)){
						length  = read_n_byte(fh, 2);
						offset3 = read_n_byte(fh, 2);
						break;
					}
					tt_seek(fh, 4, SEEK_CUR);
				}
				cmtt_info.f_type = 3;
				if(offset3 != -1){
					char name0buf[0x100];

					lseek(fh, offset + offset2 + offset3, SEEK_SET);
					if(length >= 0x100)
						length = 0xff;
					read(fh, name0buf, length);
					name0buf[length] = 0;
					length /= 2;
					if(name0buf[0] == 0){
						for(i = 0; i < length; i++)
							name0buf[i] = name0buf[2*i + 1];
						name0buf[i] = 0;
					}

					for(j = 0; j < sizeof(ttid)/sizeof(struct TTID); j++){
						if(strstr(name0buf, ttid[j].name)){
							cmtt_info.f_type = ttid[j].type;
							break;
						}
					}
				}
				break;

			default:
				break;
		}
	}
	if (item != 0x7f) return (NULL);
	return ((uchar *)&cmtt_info);
}

/*************************************************************
*	get_glyph_offset
*	glyph データの先頭アドレスを取得
**************************************************************/
static ulong get_glyph_offset(int fh, uint index)
{
	ulong offset;

#ifdef	USE_ETF
	if(fh <= 0 && fh >= -2){
		int *ptm, num;
		if(!etf_font)
			error(PROGRAM_STOP, "Internal Error (etf_font)");
		num = ((FONT_INDEX *)(etf_font + glyph.IndexBase))->num - 1;
		ptm = (int *)(etf_font + glyph.GlyphBase + (
			((FONT_INDEX *)(etf_font + glyph.IndexBase))->Coffset)); 
		for( ; ;){
			if(num-- < 0)
				return EXCEPTION;
			if(*ptm++ == index){
				offset = *ptm;
				switch(fh){
					case 0:
						goto ex;
					case -1:
						goto ex1;
					default:
						goto ex2;
				}
			}
			ptm++;
		}
	}
#endif
	/* glyph データの位置を求める */
	if (glyph.indexToLocFormat == 0) {		/* short format */
		tt_seek(fh, glyph.IndexBase + ((long)index << 1), SEEK_SET);
		offset = (ulong)read_n_byte(fh, 2) << 1;
	} else {								/* long format */
		tt_seek(fh, glyph.IndexBase + ((long)index << 2), SEEK_SET);
		offset = (ulong)read_n_byte(fh, 4);
	}
	/* glyph データの位置に seek して，輪郭，制御点の数を調べる */
ex:	tt_seek(fh, glyph.GlyphBase + offset, SEEK_SET);
	glyph.num_cts  = (short int)read_n_byte(fh, 2);
	tt_seek(fh, 8 + ((glyph.num_cts - 1) << 1), SEEK_CUR);
	glyph.num_pts  = (uint)read_n_byte(fh, 2) + 1;
ex1:
	tt_seek(fh, glyph.GlyphBase + offset, SEEK_SET);
ex2:
	return(offset);
}

/*************************************************************
*	ttf_metrics
*	欧文 TT font の metrics を得る
**************************************************************/
void ttf_metrics(FONT_INFO *font, int char_code, PREAMBLE *preamble)
{
	int fh, org_code;
	long lsb, adv;
	ulong offset;
	uint index;
	double dotsize, tmp;

	/* glyph index を求める */

	org_code = char_code;
	if (font->ext.fh <= 0)
		font->ext.fh = openf(font->name, O_RDONLY | O_BINARY);
	fh = font->ext.fh;
	cmtt_ptr = (CMTT_INFO far *)(font->pk + 4);

	if(cmtt_ptr->f_type > 256)
		char_code = TransEuroTTCode(char_code, cmtt_ptr->f_type);
	else{
		switch( (cmtt_ptr->f_type >> 1) & 7){
			case(0):
				char_code = TransEuroTTCode(char_code, 0);	/* BaKoMa */
				break;

			case(1):
				if ((char_code & 0x7f) <= 0x20) char_code ^= 0x80;
				else if (char_code == 0x7f) char_code = 0xa1;
				break;

			case(2):
				if(cmtt_ptr->C2IndexFormat != 0)
				char_code |= 0xf000;
				break;

			default:
				break;
		}
	}
	if (cmtt_ptr->C2IndexFormat == 0) {				/* format 0 */
		tt_seek(fh, cmtt_ptr->CmapBase0 + char_code, SEEK_SET);
		index = (uchar)read_n_byte(fh, 1);
	}else if (cmtt_ptr->C2IndexFormat == 4) {		/* format 4 */
		index = GetGF4(fh, char_code);
		if(char_code == 0xb7 && index == 0)
			index = GetGF4(fh, 0x2219);				/*  a bug of BaKoMa */
		if(index == 0){
			int cc;
			cc = TransEuroTTCode(char_code, 2);
			if(cc && cc != char_code)
				index = GetGF4(fh, cc);
		}
	}else {											/* format 6 */
		char_code -= cmtt_ptr->FirstCode;
		if (char_code < 0 || char_code >= cmtt_ptr->EntryCount) {
			index = 0;
		} else {
			tt_seek(fh, cmtt_ptr->CmapBase + (char_code << 1), SEEK_SET);
			index = (uint)read_n_byte(fh, 2);
		}
	}

	/* hmtx table の advance width, left side bearing を読む */
	offset = (index < cmtt_ptr->numOfHMetrics)?
		(index << 2) : ((cmtt_ptr->numOfHMetrics - 1) << 2);
	tt_seek(fh, cmtt_ptr->HmtxBase + offset, SEEK_SET);
	adv = (uint)read_n_byte(fh, 2);
	if (index >= cmtt_ptr->numOfHMetrics) {
		offset = (cmtt_ptr->numOfHMetrics + offset) << 1;
		tt_seek(fh, cmtt_ptr->HmtxBase + offset, SEEK_SET);
	}
	lsb = (short int)read_n_byte(fh, 2);

	glyph.IndexBase = cmtt_ptr->IndexBase;
	glyph.GlyphBase = cmtt_ptr->GlyphBase;
	glyph.indexToLocFormat = cmtt_ptr->indexToLocFormat;
	glyph.unitsPerEm = cmtt_ptr->unitsPerEm;

	offset = get_glyph_offset(fh, index);

	/* glyph のバウンダリより metrics を算出 */
	tt_seek(fh, 2, SEEK_CUR);
	cmtt_ptr->xMin = (short int)read_n_byte(fh, 2);
	cmtt_ptr->yMin = (short int)read_n_byte(fh, 2);
	cmtt_ptr->xMax = (short int)read_n_byte(fh, 2);
	cmtt_ptr->yMax = (short int)read_n_byte(fh, 2);

#define CEIL(X)  (((X) > (int)(X)) ? ((int)(X) + 1) : ((int)(X)))
#define FLOOR(X) (((X) < (int)(X)) ? ((int)(X) - 1) : ((int)(X)))

	/* dotsize = TT font の座標系における 1 dot の大きさ */
	dotsize = (double)cmtt_ptr->unitsPerEm
			/ (double)sptopixel(font->size_para);
	tmp = (double)cmtt_ptr->xMin / dotsize;
	cmtt_ptr->xMin = FLOOR(tmp) * dotsize;
	tmp = (double)cmtt_ptr->xMax / dotsize;
	cmtt_ptr->xMax = CEIL(tmp) * dotsize;
	tmp = -(double)lsb / dotsize;
	preamble->pitch_offset = CEIL(tmp);
	preamble->width = (double)(cmtt_ptr->xMax-cmtt_ptr->xMin) / dotsize + 0.5;

	dotsize = (double)cmtt_ptr->unitsPerEm
			/ (double)vtopixel(font->size_para);
	tmp = (double)cmtt_ptr->yMin / dotsize;
	cmtt_ptr->yMin = FLOOR(tmp) * dotsize;
	tmp = (double)cmtt_ptr->yMax / dotsize;
	cmtt_ptr->yMax = CEIL(tmp) * dotsize;
	preamble->depth_offset = (double)cmtt_ptr->yMax / dotsize + 0.5;
	preamble->height = (double)(cmtt_ptr->yMax-cmtt_ptr->yMin) / dotsize + 0.5;

	if (cmtt_ptr->f_have_tfm == TRUE) {		/* tfm があればそれを利用 */
		preamble->tfm_width =
			mult20(index = 
				tfm_width(font->pk + sizeof(CMTT_INFO) + 4, org_code),
				font->size_para);
	} else {
		preamble->tfm_width = ((((long)(adv) * (font->size_para >> 4))
							/ cmtt_ptr->unitsPerEm) << 4);
	}
	/* glyph データ先頭に seek する */
	tt_seek(fh, cmtt_ptr->GlyphBase + offset, SEEK_SET);
#ifdef	USE_ETF
	if(f_make_etf)
		SetETFindex(NULL, 0, index, lsb, 0, 4);
#endif
}


/*************************************************************
*	seek_to_tt_data
*	和文 TrueType font file の glyph データ先頭までシークする
**************************************************************/
int seek_to_tt_data(VPARA_TBL *tbl_ptr)
{
	int font_no, tti_fh, ttf_fh;
	uint gindex;
	ulong offset;

	font_no = tbl_ptr->font_no;
	if ((tti_fh = vfont[font_no]->v_fh[1]) <= 0) return (FAILURE);
	ttf_fh = tbl_ptr->vfn_file;

	if ((tbl_ptr->char_code >> 8) - 0x21 >= TTinfo[font_no]->MaxJIS) {
		return (FAILURE);
	}
	/* glyph index を求める */
	
	offset = TTinfo[font_no]->CodeTable + tbl_ptr->v_code * 2L;
	tt_seek(tti_fh, offset, SEEK_SET);
	gindex = (uint)read_n_byte(tti_fh, 2);
	if (gindex == 0) return (FAILURE);		/* 該当 glyph が無い */

	/* glyph データ先頭に seek する */
	glyph.IndexBase = TTinfo[font_no]->IndexBase;
	glyph.GlyphBase = TTinfo[font_no]->GlyphBase;
	glyph.indexToLocFormat = 1;
	glyph.unitsPerEm = TTinfo[font_no]->unitsPerEm;
	/* offset = */
	get_glyph_offset(ttf_fh, gindex);
	return (TRUE);
}

/*************************************************************
*	get_tt_glyph
*	glyph 情報の取得
**************************************************************/
int get_tt_glyph(VPARA_TBL *tbl_ptr)
{
	uint i;
	int font_no, fh, poff;
	static long seekp_sav;

	font_no = tbl_ptr->font_no;
	fh = tbl_ptr->vfn_file;

	if (f_more_glyph != TRUE) {
		tt_seek(fh, 10, SEEK_CUR);
		if (glyph.num_cts == 0) return (FAILURE);
		if (glyph.num_cts == -1) goto composite;
		if (glyph.num_cts < -1) goto err;
		if (get_tt_list(fh) == FAILURE) goto err;
	} else {	/* composite glyph */
		tt_seek(fh, seekp_sav, SEEK_SET);
composite:
		seekp_sav = load_composite_glyph(tbl_ptr);
		if (seekp_sav == -1) goto err;
	}

	/* 座標系変換 */
	poff = (tbl_ptr->font_type == CMTTF || tbl_ptr->font_type == ETF_FONT)?
		cmtt_ptr->xMin : TTinfo[font_no]->xMin;
		for (i = 0; i < glyph.num_pts; i++) {
		glyph.xlist[i] = ((long)(glyph.xlist[i] - poff) * MAX_RANGE)
						/ glyph.unitsPerEm;
	}
	poff = (tbl_ptr->font_type == CMTTF || tbl_ptr->font_type == ETF_FONT)?
		cmtt_ptr->yMax : (glyph.unitsPerEm + TTinfo[font_no]->yMin);
	for (i = 0; i < glyph.num_pts; i++) {
		glyph.ylist[i] = ((long)(poff - glyph.ylist[i]) * MAX_RANGE)
						/ glyph.unitsPerEm;
	}
	return (TRUE);

err: 
	error(WARNING, "[TTfont] data error.(%#x) %s",
		tbl_ptr->char_code, tbl_ptr->v_font_name);
	return (FAILURE);
}

/*************************************************************
*	load_composite_glyph
*	composite glyph の処理
**************************************************************/
static long load_composite_glyph(VPARA_TBL *tbl_ptr)
{
	double Trans[2][3];
	uint flags, index;
	int fh, i, x, y;
	ulong offset;
#ifdef	USE_ETF
	ulong offset_2;
#endif

	fh = tbl_ptr->vfn_file;
	flags = (uint)read_n_byte(fh, 2);
	index = (uint)read_n_byte(fh, 2);
	if (flags & ARG_1_AND_2_ARE_WORDS) {
		Trans[0][2] = (short int)read_n_byte(fh, 2);
		Trans[1][2] = (short int)read_n_byte(fh, 2);
	} else {
		i = (short int)read_n_byte(fh, 2);
		Trans[1][2] = (char)(i & 0xff);
		Trans[0][2] = (char)(i >> 8);
	}
	Trans[0][1] = Trans[1][0] = 0.0;
	Trans[0][0] = Trans[1][1] = 1.0;
	if (flags & WE_HAVE_A_SCALE) {
		Trans[0][0] = Trans[1][1] = read_F2Dot14(fh);
	} else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) {
		Trans[0][0] = read_F2Dot14(fh);
		Trans[1][1] = read_F2Dot14(fh);
	} else if (flags & WE_HAVE_A_TWO_BY_TWO) {
		Trans[0][0] = read_F2Dot14(fh);
		Trans[1][0] = read_F2Dot14(fh);
		Trans[0][1] = read_F2Dot14(fh);
		Trans[1][1] = read_F2Dot14(fh);
	}
	offset = read_n_byte(fh, 0);
	if(get_glyph_offset(fh, (fh)?index:(index|ETF_COMPOSITE)) == EXCEPTION)
		error(FONT_MISMATCH, "Error in ETF-%d(composite glyph)");

#ifdef	USE_ETF
	offset_2 = read_n_byte(fh, 0);
#endif
	tt_seek(fh, 10, SEEK_CUR);
	if (get_tt_list(fh) == FAILURE) return (-1);
/*	printf("%10.4f%10.4f%10.4f\n", Trans[0][0], Trans[0][1], Trans[0][2]);
	printf("%10.4f%10.4f%10.4f\n", Trans[1][0], Trans[1][1], Trans[1][2]);*/
	/* 変形 */
	for (i = 0; i < glyph.num_pts; i++) {
		x = glyph.xlist[i];
		y = glyph.ylist[i];
		glyph.xlist[i] = x * Trans[0][0] + y * Trans[0][1] + Trans[0][2];
		glyph.ylist[i] = x * Trans[1][0] + y * Trans[1][1] + Trans[1][2];
	}
#ifdef	USE_ETF
	if(f_make_etf)
		SetETFindex(NULL, index, offset, offset_2, 
			read_n_byte(fh,0), 2);
#endif
	f_more_glyph = (flags & MORE_COMPONENTS)? TRUE : FALSE;
	return (offset);
}

/*************************************************************
*	get_tt_list
*	xlist, ylist の取得
**************************************************************/
static int get_tt_list(int fh)
{
	uint i, j;
	int cp, buffsize;

	/* ワークバッファの確保 */
	buffsize = sizeof(int) * (glyph.num_cts + glyph.num_pts + glyph.num_pts)
			 + sizeof(char) * glyph.num_pts;
	glyph.end_pts = (uint *)marea(buffsize);
	glyph.xlist = (int *)(&glyph.end_pts[glyph.num_cts]);
	glyph.ylist = (int *)(&glyph.xlist[glyph.num_pts]);
	glyph.flist = (uchar *)(&glyph.ylist[glyph.num_pts]);
	/* 各輪郭の終点リスト */
	for (i = 0; i < glyph.num_cts; i++) {
		glyph.end_pts[i] = (uint)read_n_byte(fh, 2);
	}
	/* instruction (hint 情報) は無視する */
	i = read_n_byte(fh, 2);		/* instruction の長さ */
	tt_seek(fh, i, SEEK_CUR);

	/* flag 情報 */
	for (i = 0; i < glyph.num_pts; i++) {
		glyph.flist[i] = (uchar)read_n_byte(fh, 1);
		if (glyph.flist[i] & REPEAT_FLAGS) {
			for (j = (uchar)read_n_byte(fh, 1);
				j > 0; j--, i++) {
				glyph.flist[i + 1] = glyph.flist[i];
			}
		}
	}
	/* x 座標 */
	cp = 0;
	for (i = 0; i < glyph.num_pts; i++) {
		if (glyph.flist[i] & XSHORT) {
			if (glyph.flist[i] & SHORT_X_IS_POS) {
				cp += (uchar)read_n_byte(fh, 1);
			} else {
				cp -= (uchar)read_n_byte(fh, 1);
			}
		} else {
			if (!(glyph.flist[i] & NEXT_X_IS_ZERO)) {
				cp += (short int)read_n_byte(fh, 2);
			}
		}
		glyph.xlist[i] = cp;
	}
	/* y 座標 */
	cp = 0;
	for (i = 0; i < glyph.num_pts; i++) {
		if (glyph.flist[i] & YSHORT) {
			if (glyph.flist[i] & SHORT_Y_IS_POS) {
				cp += (uchar)read_n_byte(fh, 1);
			} else {
				cp -= (uchar)read_n_byte(fh, 1);
			}
		} else {
			if (!(glyph.flist[i] & NEXT_Y_IS_ZERO)) {
				cp += (short int)read_n_byte(fh, 2);
			}
		}
		glyph.ylist[i] = cp;
	}
	glyph.cp = -1;
	glyph.cc = 0;
	return (TRUE);

}

/*************************************************************
*	get_tt_xy
*	座標データの取得
**************************************************************/
int get_tt_xy(LOCATE *locate)
{
	static int sp, ep;				/* 現輪郭線の始点、終点のポインタ */
	static int p1, p2, p3;			/* スプラインを構成する制御点のポインタ */
	static int t = -1, step;		/* スプライン曲線上の時刻 (t=0,1,...,15) */
	static LOCATE k1, k2, k3;
	int x, y;
	int len;

	if (t < 0) {					/* スプラインの基底を初期化 (256 倍) */
		for (t = 1; t < 16; t++) {
			basis[0][t - 1] = (16 - t) * (16 - t);
			basis[1][t - 1] = 128 - (t - 8) * (t - 8) * 2;
			basis[2][t - 1] = t * t;
		}
	}
	if (glyph.cp < 0) {				/* 初期設定 */
		t = sp = 0;
		ep = glyph.end_pts[0];
		glyph.cp = 0;
	}

	if (t > 0) {				/* スプラインの途中 */
		x = ((long)basis[0][t - 1] * k1.x
		   + (long)basis[1][t - 1] * k2.x
		   + (long)basis[2][t - 1] * k3.x + 128L) >> 8;
		y = ((long)basis[0][t - 1] * k1.y
		   + (long)basis[1][t - 1] * k2.y
		   + (long)basis[2][t - 1] * k3.y + 128L) >> 8;
		t += step;
		if (t >= 16) {
			t = 0;
			glyph.cp++;
		}
	} else {
retry:
		if (glyph.cp > ep) {
			if (glyph.cp >= glyph.num_pts) {
				if (glyph.end_pts != NULL) {
					Free((void *)glyph.end_pts);
					glyph.end_pts = NULL;
				}
				if (f_more_glyph == TRUE)
					return (FALSE);		/* composite glyph */
				return (NOMORE);		/* 全データの最後 */
			}
			sp = ep + 1;
			ep = glyph.end_pts[++glyph.cc];
			t = 0;
			return (NOMORE);			/* 輪郭線の最後 */
		}
		p1 = glyph.cp;
		p2 = (p1 < ep)? (p1 + 1) : sp;
		p3 = (p2 < ep)? (p2 + 1) : sp;
		if (glyph.flist[p1] & glyph.flist[p2] & ONCURVE) {	/* 直線 */
			x = glyph.xlist[p1];
			y = glyph.ylist[p1];
			glyph.cp++;
		} else if (glyph.flist[p2] & ONCURVE) {
			glyph.cp++;
			goto retry;
		} else {								/* 2 次 B スプライン */
			if (glyph.flist[p1] & ONCURVE) {
				k1.x = glyph.xlist[p1];
				k1.y = glyph.ylist[p1];
			} else {
				k1.x = (glyph.xlist[p1] + glyph.xlist[p2] + 1) / 2;
				k1.y = (glyph.ylist[p1] + glyph.ylist[p2] + 1) / 2;
			}
			k2.x = glyph.xlist[p2];
			k2.y = glyph.ylist[p2];
			if (glyph.flist[p3] & ONCURVE) {
				k3.x = glyph.xlist[p3];
				k3.y = glyph.ylist[p3];
			} else {
				k3.x = (glyph.xlist[p2] + glyph.xlist[p3] + 1) / 2L;
				k3.y = (glyph.ylist[p2] + glyph.ylist[p3] + 1) / 2L;
			}
			/* step が小さいほど精度は高くなる */
			len = abs(k3.x - k2.x) + abs(k3.y - k2.y)
				+ abs(k2.x - k1.x) + abs(k2.y - k1.y);
			if (len > 500) {
				step = 1;
			} else if (len > 100) {
				step = 2;
			} else {
				step = 4;
			}
			x = k1.x;
			y = k1.y;
			t += step;
		}
	}
	locate->x = x;
	locate->y = y;
	return (TRUE);
}

/*************************************************************
*	read_F2Dot14
*	Fixed point format 読み込み
**************************************************************/
static double read_F2Dot14(int fh)
{
	int Mantissa, Fraction;

	Fraction = read_n_byte(fh, 2);
	Mantissa = Fraction >> 14;
	Fraction &= 0x3fff;
	return ((double)Mantissa + (double)Fraction / 16384.0);
}

static uchar *buf = (uchar *)bufx;
static int bp;
static long seekp;


/*************************************************************
*	tt_seek
*	fromwhere = SEEK_SET : 絶対指定
*	else : ポインタを進める (offset << VF_BUF_SIZE)
*************************************************************/
static long tt_seek(int fh, long offset, int fromwhere)
{
#ifdef	USE_ETF
	if(fh == 0 || fh == -1){
		if(!etf_font)
			error(PROGRAM_STOP, "Internal error(tt_seek)");
		seekp = 0;
		if(fromwhere == SEEK_SET){
			bp = offset;
		}else
			bp += offset;
		buf = etf_font;
	}else
#endif
	if (fromwhere == SEEK_SET) {
		buf = (uchar *)bufx;
		seekp = offset;
		lseek(fh, offset, SEEK_SET);
		read(fh, buf, VF_BUF_SIZE);
		bp = 0;
	} else {
		buf = (uchar *)bufx;
		bp += offset;
		while (bp >= VF_BUF_SIZE) {
			read(fh, buf, VF_BUF_SIZE);
			seekp += VF_BUF_SIZE;
			bp -= VF_BUF_SIZE;
		}
	}
	return (seekp + bp);
}

/*************************************************************
*	低水準入出力関数版 n byte 読み込み
*	n = 0 : 現在のポインタ返す (tell)
*	n > 0 : n byte (n <= 4) 読み込み
**************************************************************/
static ulong read_n_byte(int fh, int n)
{
	ulong num;

	if (n <= 0) return (seekp + bp);
	if (n > 4) n = 4;

	num = 0;
	while (1) {
		switch(n--){
			case 0:
				return num;
			case 1:
				num += buf[bp];
				break;
			case 2:
				num += buf[bp] << 8;
				break;
			case 3:
				num += buf[bp] << 16;
				break;
			case 4:
				num += buf[bp] << 24;
				break;
		}
		if (++bp >= VF_BUF_SIZE && fh) {
			seekp += VF_BUF_SIZE;
			read(fh, buf, VF_BUF_SIZE);
			bp = 0;
		}
	} 
}

/***************************************************************
*  					ETF Fonts routine
****************************************************************/

/*		******************  GetFont  *****************

1. BOOL IsETF(FONT_INFO *font, char *name, int fig);

2. BOOL etf_metrics(unsigned char **pk_ptr, FONT_INFO *font, int char_code, 
	PREAMBLE *preamble);

3. switch(font->etftype)

CMTTF:
  get_cmttfont(new_code, preamble, font);

TT_FONT:
  get_ettfont(new_code, preamble, font);
  
PK_FONT:
  decode_pk(pk, preamble, flag_byte, font);

VIRTUAL_FONT:
  memcpy(preamble->raster, pk, preamble->byte_width);

		***************************************		*/

/********************************************************
*
*				Font Embedding
*
*
	Top Header;			// 32 byte
	Mapping Table;		// currently not used
	Font Table;			// array of the structure with the fiexed size(24 byte)
	-------------------
	GLYPH_SET[];		// Glyph Data for characters in a font
	FONT_HEADER:		// Data for font
	CODE_TABLE[];		// Code -> Glyph offset
	----------
	GLYPH_SET[];		// Glyph Data for characters in a font
	FONT_HEADER:		// Data for font
	CODE_TABLE[];		// Code -> Glyph offset
	----------
	.....
************************************************************
--- Header 32 byte ---
	id[2] :     EF(id)
	ver[2]:	    Version
	size[4]:    file size

	dpi[2]:	    default dpi	  (&0x8000:ON -> &0x7fff: offset to the list of dpi)
	type[2]:    included font
	glyph[4]:   glyph base

	fnum[4]:    number of fonts included
	ad_font[4]: offset of font table

	map[4]:	    number of mapping font
	off_map[4]: offset of mappint table

--- list of dpi ----
	dpi[2][]:	terminated by 0		<- list of dpi

--- String Data	?? byte ---
string data of name of fonts and mapping

--- Font Mapping  (not used) --

struct
{
	int org_name;
	int off_trans;
} MAP_NAME[];

--- Font Table ---

struct
{
	int name;		// name of the fonts (to be called)
	int resol;		// resolution  (resol | (base_resol << 16))
	int type;		// font_type (CMTTF, TT_FONT, PK_FONT, etc.)
	int num;		// number of characters
	int Hoffset;	// offset to the Header (Glyph Base)
	int Coffset;	// offset of table : code -> glyph (Glyph Base)
} FONT_INDEX[fnum];

---  Here is Glyph Base ---
--- Glyph Data / Font Header / Code Table  for each Font ---
struct
{
	struct  PRE_GLYPH;
	unsigned char GLYPH[];		<- CODE_TABLE[<num>].glyph_offset (Glyph Base)
} GLYPH_SET[FONT_INDEX[<n>].num];

unsigned char FONT_HEADER_<n>[];	<- FONT_INDEX[<n>].Hoffset (Glyph Base)

struct
{
	int char_code;
	int glyph_offset;
} CODE_TABLE[FONT_INDEX[<n>].num];	<- FONT_INDEX[<n>].Coffset (Glyph Base)
***********************************************************

CMTTF:  TrueType font (1 byte code) expanded by dviout
	{
		short	int lsb;
		int		tmf_width;
		uchar	glyph_data[];	<- Glyph offset
	} GLYPH_SET[];

	{
		{
			int	char_code;
			int	tfm_width;
		} tfm_width[extra];	
		int		unitsPerEm;		<- Header offset
		int		extra;
	};

	{
		int		char_code;
		int 	glyph_offset;
	} CODE_TABLE[c_num+1];		<- Code offset;
	char		file_name[];	NULL terminated

	Remark:	GLYPH_SET[] and CODE_TABLE[] may be common for several fonts.
	CODE_TABLE[c_num].char_code=	0
	CODE_TABLE[c_num].glyph_offset=	(sizeof(PRE_GLYPH)<<24)			// = 6
									+ sizeof(last glyph_data[])

TT_FONT: Japanse TrueType expanded by dviout
	{
		uchar	glyph[data];
	} GLYPH_SET[];				<- Glyph offset

	{
		{
			int	char_code;
			int	tfm_width;
		} tfm_width[extra];
		struct ETT_FONT;		<- Header offset
	};

	{
		int		char_code;
		int 	glyph_offset;
	} CODE_TABLE[cnum+1];		<- Code offset;
	char		file_name[];	NULL terminated;

	Remark:	GLYPH_SET[] and CODE_TABLE[] may be common for several fonts.

WINTT_FONT: TrueType font (1 byte code) expanded by Windows API
	{
	};				empty

	{
		char	font_name[];	<- Header offset
	};

	{
		int		char_code;
		int		tfm_width[];
	} CODE_TABLE[];				<- Code offset;

WINJTT: Japanese TrueType font expanded by Windows API
	{
	};				empty

	{
		char	font_name[];	<- Header offset
	};

	{
		uchar	jfm_data[];		<- Code offset
	};

	Remark: jfm_data[] may be common for several fonts.

PK_FONT: PK font
	{
		uchar	flag_byte;
		uchar	glyph_data[];	<- Glyph offset
	} GLYPH_SET[];

	{
	};				empty

	{
		int		char_code;
		int 	glyph_offset;
	} CODE_TABLE[cnum+1];		<- Code offset;

VIRTUAL_FONT: Virtual font
	{
		int		glyph_size;
		int		tfm_width;
		uchar	glyph_data[];	<- Glyph offset
	} GLYPH_OFFSET[];

	{
		uchar	font_list[];	<- Header offset
	};

	{
		int		char_code;
		int 	glyph_offset;
	} CODE_TABLE[];			<- Code offset;

***************************************************************/


#ifdef USE_ETF
/****************************************
*		Release the loaded ETF
****************************************/
void FreeETF(void)
{
	if(etf_font)
		ClearFont();
	etf_map_top = etf_jmap_top = 0;
	Free0(etf_font);
	etf_font = NULL;
	EnableETFInfo(FALSE);
}

/***************************************
*	Load ETF form the current DVI file
***************************************/
char *LoadETF(char *name)
{
	FILE *fp;
	int *idx;
#define	ETF_NAME	"dviout.etf"

	if(!f_use_etf){
		if(etf_font)
			FreeETF();
		return NULL;
	}
	if(etf_font == NULL){
		ClearFont();
		if(name){
			fp = fopenf(name, "rb");
			if(fp == NULL)
				return NULL;
			etf_size = filelength(fileno(fp));
			etf_font = (char*)marea(etf_size);
			fread(etf_font, 1, etf_size, fp);
			fclose(fp);
		}else if((etf_size = GetAddMemory(ETF_NAME, NULL, 0)) >= 0x20){
			etf_font = (char*)marea(etf_size);
			GetAddMemory(ETF_NAME, etf_font, etf_size);
		}
		if(etf_size < 0x20 || (etf_font[0] != 'E' && etf_font[1] != 'T')){
unload:		FreeETF();
			return NULL;
		}
		etf_version = (etf_font[3] << 16) + etf_font[2];
		if(etf_version <= 3){
			error(WARNING, "ETF(Font Embedding) Ver.%d.%d is not supported.\n"
				"Current: Ver.%x.%02x",
				etf_font[3], etf_font[2], ETF_VERSION, ETF_SUBVER);
			goto unload;
		}
		idx = (int *)(etf_font + 12);
		etf_glyph	= etf_font + *idx++;
		etf_max_idx	= *idx++;
		etf_idx	= (FONT_INDEX *)(etf_font + *idx++);
		etf_max_map	= *idx++;
		etf_map = (int *)(etf_font + *idx);
		EnableETFInfo(TRUE);
	}
	return etf_font;
}

/*************************************
*  Get address of the Font Header
**************************************/

unsigned char *GetHoffset(FONT_INFO *font)
{
	return etf_glyph + ((FONT_INDEX *)(font->pk))->Hoffset;
}

extern const int s_ratio[3];
extern int k_scale;
extern int k_base;

void OpenETT(FONT_INFO *font)
{
	int base_ratio, kk_scale, ptwork, width, height, size, i;
	ETT_FONT *ett;
	KFONT *kf;

	ett = (ETT_FONT *)GetHoffset(font);
	base_ratio = ett->tfm_depth / 
		((height = ett->tfm_depth + ett->tfm_height) >> 10);
	base_ratio = (base_ratio * 1000) >> 10;
	kk_scale = k_scale*952/1000;
	ptwork = mult20(height, font->size_para / 250 * kk_scale /4);
	font->f_goth = ett->f_goth;
	height = (font->f_goth & F_TATE)? sptopixel(ptwork) : vtopixel(ptwork);
	ptwork = mult20(ett->tfm_width, font->size_para / 250 * kk_scale);
	width = (font->f_goth & F_TATE)? vtopixel(ptwork/4) : sptopixel(ptwork/4);

	if(font->f_goth & F_TATE){
		i = width;
		width = height;
		height = i;
	}
	width = width * ett->width_adj/1000;
	height = height * ett->height_adj/1000;
	if ((int)'b' <= ett->long_wide && ett->long_wide <= (int)'e') 
		height = (int)((long)width * 10 / (10 - (ett->long_wide - (int)'a')));
	else if ((int)'g' <= ett->long_wide && ett->long_wide <= (int)'j') 
		height = (int)((long)width * (10 - (ett->long_wide - (int)'f')) / 10);
	if (ett->slant != (int)'a') {
		i = (ett->slant - (int)'b') % 3;
		if ((int)'b' <= ett->slant && ett->slant <= (int)'g') 
			width = (int)((long)width * (MAX_VALUE + s_ratio[i]) 
				/ (MAX_VALUE + 1));
		else
			height = (int)((long)height * (MAX_VALUE + s_ratio[i])
				/ (MAX_VALUE + 1));
	}
	if(font->f_goth & F_TATE){
		font->k_width = height;
		font->k_height = width;
	}else{
		font->k_width = width;
		font->k_height = height;
	}
	size = (width + 7) / 8 * height;

	font->ext.kdir = kf = (KFONT *)marea(KFONT_SIZE);
	kf->name = NULL;
	kf->width = width;
	kf->height = height;
	kf->size = size;
	kf->fh = 0;
	if (font->f_goth & (K_SCALE|K_SCALE2))
		i = font->k_height;
	else
		i = (font->f_goth & F_TATE)?kf->width:kf->height;
	kf->base = ((1000 - base_ratio - 
		((font->f_goth & F_TATE)? 0 : k_base)) * i + 500) / 1000;
}


/***************************************
*	A routine only called from  IsETF()
****************************************/
static double Closer(double x, double y)
{
	double xx, yy;

	xx = (x >= 1)?x:(1/(x*x));
	yy = (y >= 1)?x:(1/(y*y));
	return (xx <= yy)?x:y;
}

char *check_etfmap(char *name)
{
	int i;

	if(etf_map_top < 0 && etf_jmap_top < 0)
		return NULL;
	if(!etf_map_top){
		etf_map_top = etf_map_end = etf_jmap_top = etf_jmap_end = -1;
		if(etf_font == NULL)
			return NULL;
		for(i = 0; i < etf_max_idx; i++){
			if(etf_idx[i].type == WINTT_FONT){
				etf_map_top = i;
				while(++i < etf_max_idx && etf_idx[i].type == WINTT_FONT);
				etf_map_end = i;
				break;
			}
		}
		for( ;i < etf_max_idx; i++){
			if(etf_idx[i].type == WINJTT_FONT){
				etf_jmap_top = i;
				while(++i < etf_max_idx && etf_idx[i].type == WINJTT_FONT);
				etf_jmap_end = i;
				break;
			}
		}
	}
	for(i = etf_map_top; i < etf_map_end; i++){
		if(!strcmp(etf_font +  etf_idx[i].name, name))
			goto find;
	}
	for(i = etf_jmap_top; i < etf_jmap_end; i++){
		if(!strcmp(etf_font +  etf_idx[i].name, name)){
find:		name = etf_glyph + etf_idx[i].Hoffset;
			return (*name)?name:NULL;
		}
	}
	return NULL;
}

/****************************************
*	Check if the font exist in ETF
*****************************************/
BOOL IsETF(FONT_INFO *font, char *name, int fig)
{
	int i, res, res0, res1, res2;
//	char *name2;
	double rel, rel0;

	if(etf_font == NULL)
		return FALSE;

//	for(i = 0; i < etf_max_map; i++){
//		if(!strcmp(name, name2 = etf_font + etf_map[i+i])){
//			name = name2 + strlen(name2) + 1;
//			break;
//		}
//	}
	res = res2 = etf_font[8] + (etf_font[9]<<8);
	if(!res)
		rel = 1;
	else if(!(res & 0x8000))
		rel = (double)res/GetXDpi();
	else{
		i = res & 0x7fff;
		for(rel = 100; (res = etf_font[i] + (etf_font[i+1]<<8)) != 0; i += 2){
			if(res == GetXDpi()){
				res2 = res;
				rel = 1;
				break;
			}
			rel0 = Closer(rel, (double)res/GetXDpi());
			if(rel0 != rel){
				res2 = res;
				rel = rel0;
			}
		}
	}
	res0 = fig*(rel-.01) - 1 + (res2 << 16);
	res1 = fig*(rel+.01) + 1 + (res2 << 16); 
	for(i = 0; i < etf_max_idx; i++){
		if(!strcmp(etf_font +  etf_idx[i].name, name)){
			if( etf_idx[i].resol != 0){
				if(etf_idx[i].resol < res0 || etf_idx[i].resol > res1)
					continue;
				font->sdpi = (rel < 1.01 && rel > 0.99)?
					fig:(etf_idx[i].resol & 0xffff);
			}
			font->pk = (unsigned char *)(etf_idx + i);
			font->etf_type = ((FONT_INDEX *)(font->pk))->type;
			font->font_type = ETF_FONT;
			if(font->etf_type == VIRTUAL_FONT)
				MakeLocalFontList(font, GetHoffset(font));
			else if(font->etf_type == TT_FONT)
				OpenETT(font);
			else if(font->etf_type == WINJTT_FONT){
				font->pk = etf_glyph + ((FONT_INDEX *)(font->pk))->Coffset;
				font->font_type = UNKNOWN;
			}else if(font->etf_type == WINTT_FONT
				&& (font->vjfm = check_wintt(font->n)) == NULL){
					font->pk = NULL;
					return FALSE;
			}
			return TRUE;
		}
	}
	return FALSE;
}

/*************************************************
*	Keep data for Image Embedding
*************************************************/
BOOL SetETFimg(char *name)
{
	ETF_IMAGE *pt;

	for(pt = &etf_img; pt->next; pt = pt->next){
		if(!strcmp(pt->next->image, name))
			return FALSE;
	}
	pt->next = (ETF_IMAGE *)marea(strlen(name) + (sizeof(ETF_IMAGE) - 2));
	pt->next->next = NULL;
	pt->next->flag = 1;
	strcpy(pt->next->image, name);
	return TRUE;
}

static void FreeETFImage(ETF_IMAGE *im)
{
	ETF_IMAGE *pt, *tmp;

	for(pt = im; pt; pt = tmp){
		tmp = pt->next;
		Free(pt);
	}
}

/*************************************************
*		Keep data for Font Embedding
*************************************************/
void SetETFindex(FONT_INFO *font, int char_code, int tfm_width, 
	int top, int last, int mode)
{
	static int offset;
	static int org_top;
	static int width = EXCEPTION;
	static int lsb;

	int i;
	ETF_INFO *etf_tmp;

	if(etf_pt >= etf_end){
		if(!etf_end){
			etf_end = ETF_BLOCK;
			etf_info = (ETF_INFO *)marea(etf_end*sizeof(ETF_INFO));
			etf_pt = 0;
		}else{
			etf_tmp = 
				(ETF_INFO*)marea((etf_end+ETF_BLOCK)*sizeof(ETF_INFO));
			memcpy(etf_tmp, etf_info, etf_end*sizeof(ETF_INFO));
			Free(etf_info);
			etf_end += ETF_BLOCK;
			etf_info = etf_tmp;
		}
	}
	etf_tmp = etf_info + etf_pt;
	switch(mode){
		case 1:			/* TTF */
			if(char_code == 0x2121){
				etf_tmp->top = 1;
				etf_tmp->end = 0;
				goto skp;
			}
		case 0:			/* CM_TTF, Virtual Font */
			etf_tmp->top = top?top:org_top;
			etf_tmp->end = last?last:(offset?offset:read_n_byte(0,0));
skp:		etf_tmp->font = font;
			for(i = 1; etf_tmp-i >= etf_info && etf_tmp[-i].font == NULL; i++)
				etf_tmp[-i].font = etf_tmp->font;	// for composite glyph
			etf_tmp->code = char_code;
			if((etf_tmp->tfm_width = tfm_width?tfm_width:width) == EXCEPTION)
				etf_error = EXCEPTION|etf_pt;
			etf_tmp->lsb = lsb;
			offset = lsb = 0;
			width = EXCEPTION;
			for(i = etf_pt - 1; i >= 0 && etf_info[i].font == NULL; i--)
				etf_info[i].font = font;
			etf_pt++;
			break;

		case 2:			/* composite glyph */
			offset = tfm_width;					/* maybe the end of glyph */
			char_code |= ETF_COMPOSITE;

		case 6:			/* WINTT_FONT, WINJTT_FONT */
			if(font && *(font->name) == '<')
				break;
			etf_tmp->tfm_width = tfm_width;		/* dummy */
			etf_tmp->font = font;
			etf_tmp->code = char_code;
			etf_tmp->top = top;
			etf_tmp->end = last;
			etf_pt++;
			break;

		case 3:			/* set start position of CM_TTF/TTF */
			offset = 0;
			org_top = read_n_byte(0,0);
			break;

		case 4:			/* set tfm_width */
			width = tfm_width;
			lsb = top;
			break;

		case 5:			/* PK */
			etf_tmp->font = font;
			etf_tmp->code = char_code;
			etf_tmp->lsb = tfm_width;			/* flag_byte */
			etf_tmp->top = top;					/* font->pk + top : tfm[]  */
			etf_tmp->end = top + last - 1;		/* last is the size */
			etf_pt++;
			break;
	}
#if	0
	if(mode < 3){
		char msg[32];

		if((i = etf_tmp->code) >= 0x21 && i < 0x7f)
			sprintf(msg, " %c ", i);
		else
			sprintf(msg, "%3d", i );

		error(C_MSG, "%d(%3d):%3d %s %6d %6d %6d %3d\n", mode, etf_pt,
			font?font->font_code:-1, msg,
			etf_tmp->tfm_width, etf_tmp->top, etf_tmp->end, etf_tmp->lsb);
	}else if(mode == 3)
		error(C_MSG, "3: %d\n", org_top);
	else
		error(C_MSG, "%d: %d\n", mode, read_n_byte(0,0));
#endif
}

static int eft_comp(ETF_INFO *arg1, ETF_INFO *arg2)
{
	int i, j;

	i = (j = arg1->font->font_type) - arg2->font->font_type;
	if(i)
		return i;
	if(j == TT_FONT)
		i = strcmp(arg1->font->ext.kdir->name, arg2->font->ext.kdir->name);
	else if(j == WINTT_FONT || j == WINJTT_FONT)
		i = strcmp(arg1->font->n, arg2->font->n);
	else
		i = strcmp(arg1->font->name, arg2->font->name);
	if(i)
		return i;
	return
		arg1->code - arg2->code;
}

char *ffname(char *fname)
{
	int top, len;
	static char name[0x20];

	top = strlen(fname);
	while(--top >= 0)
		if(fname[top] == '\\' || fname[top] == ':')
			break;
	top++;
	for(len = 0; len < 0x1f; len++){
		name[len] = fname[top++];
		if(name[len] == '.' || name[len] == 0)
			break;
	}
	name[len] = 0;
	return name;
}

/**************************************************
*	Embed a Virtual font into the current DVI file
**************************************************/
int WriteVirtualETF(FONT_INFO *font, FILE *fp)
{
	FONT_INFO *local_font;
	int cmd, pos = 0;
	unsigned char *pk, *pk0;

	pk = font->pk;
	move_ptr(pk, 2);	/* skip pre(247), id(202) */
	cmd = get_ubyte(pk);	/* size of a comment */
	move_ptr(pk, cmd + 8);	/* skip comment, check sum, design size */

	for(local_font = font->ext.local_font; local_font; 
	  local_font = local_font->next_font){
		pk0 = pk;
		cmd = get_ubyte(pk);
		pk += cmd - FNT_DEF_1 + 1;
		pk += 12;
		cmd = get_ubyte(pk);
		cmd += get_ubyte(pk);
		pk += cmd;
		if(local_font->font_type > ONDEMAND2){
			while(pk0 < pk){
				pos++;
				fputc(*pk0++, fp);
			}
		}
	}
	fputc(PRE, fp);
	return(pos+1);
}

static void putshort(int num, FILE *fp)
{
	fputc(num & 0xff, fp);
	fputc((num>>8) & 0xff, fp);
}


static int WriteECMHeader(ETF_INFO *ett, short int *fdx, int last, int pos,
	FILE *fp)
{
	FONT_INFO *finfo;
	int i, j, k, old_code, exf;
#define	DONE	-30000

	for(i = 0; i < last; i++){
		ett[i].lsb = 0;		// unnecessary?
		if(fdx[i] == DONE)
			continue;
		old_code = -1;
		exf = 0;
		finfo = ett[i].font;
		for(j = i; j < last; j++){
			if(fdx[i] == DONE || strcmp(ett[j].font->n, finfo->n))
				continue;
			if(j > i)
				fdx[j] = DONE;
			if(ett[j].code == old_code)
				continue;
			old_code = ett[j].code;
			for(k = j; k >= 0 && ett[k].code == old_code; k--);
			if(ett[k+1].tfm_width == ett[j].tfm_width)	// compare with normal
				continue;
			exf++;
			putint(old_code, fp);			// write exceptional width
			putint(ett[j].tfm_width, fp);
		}
		if(i)
			fdx[i] = -extra++ - 2;
		pos += exf*(2*sizeof(int));
		ett[i].lsb = pos;
		if(finfo->pk == NULL)
			finfo->pk = load_pk(finfo->name, finfo->n);
		putint(((CMTT_INFO *)(finfo->pk + 4))->unitsPerEm, fp);
		putint(exf, fp);
		pos += 2*sizeof(int);
nxt:	/* */ ;
	}
	for(i = 0; i < last; i++)
		if(fdx[i] == DONE)
			fdx[i] = -1;
	return pos;
}

static int WriteETTHeader(ETF_INFO *ett, short int *fdx, int last, int pos,
	FILE *fp)
{
	int *idx;
	int i, j, k, count, font_no, width, exf, old_code;
	FONT_INFO *font;
	V_JFM *vjfm;
	JFM_DATA *jtfm;

	idx = (int *)marea(last*sizeof(int));
	count = 0;
	for(i = 0; i < last; i++){
		ett[i].lsb = 0;		// unnecessary?
		for(j = 0; j < count; j++){
			if( !strcmp(ett[idx[j]].font->n, ett[i].font->n) ){
				fdx[i] = fdx[idx[j]];	/* same TeX font (& dpi) */
				goto nxt;
			}
		}
		idx[count++]=i;
		if(i)
			fdx[i] = -extra++ - 2;
nxt:	/* */ ;
	}
	Free(idx);
	for(k = fdx[0], i = 0; i < last; ){

		font = ett[i].font;
		vjfm = get_vjfm(font->ext.kdir->fh);
		font_no = vjfm->font_no;
		if (!font->pk)
			font->pk = load_pk(font->name, font->n);
		jtfm = jfm_read(font, 0);
		width = jtfm->width;

		old_code = -1;
		for(exf = 0, j = i; j < last; j++){
			if(fdx[j] != k || 
			   ett[j].tfm_width == width || ett[j].code == old_code)
				continue;
			exf++;
			putint(old_code = ett[j].code, fp);		// write exceptional width
			putint(ett[j].tfm_width, fp);
		}

		pos += exf*(sizeof(int)*2);
		ett[i].lsb = pos;

		putint(width, fp);							// tfm_width
		putint(jtfm->height, fp);					// tfm_height
		putint(jtfm->depth, fp);					// tfm_depth

		putshort(TTinfo[font_no]->unitsPerEm, fp);	// unitsPerEM;
		putshort(TTinfo[font_no]->xMin, fp);		// xMin
		putshort(TTinfo[font_no]->yMin, fp);		// yMin

		putshort(exf, fp);							// extra width data
		putshort(vfont[font_no]->yoffset, fp);		// yoffset

		putshort(vfont[font_no]->width_adj, fp);	// width_adj
		putshort(vfont[font_no]->height_adj, fp);	// height_adj

		putshort(font->f_goth, fp);					// f_goth

		putshort(vjfm->long_wide, fp);				// long_wide
		putshort(vjfm->slant, fp);					// slant
		putshort(vjfm->draw_sw, fp);				// draw_sw
		putshort(vjfm->threshold, fp);				// threshold
		putshort(vjfm->thin, fp);					// thin
		putshort(vjfm->_xfat, fp); 					// _xfat
		putshort(vjfm->_yfat, fp);					// _yhat
		putshort(vjfm->rotation, fp);				// rotation

		pos += sizeof(ETT_FONT);

		while(fdx[i] >= k){
			if(++i >= last)
				goto quit;
		}
		k = fdx[i];
	}
quit:
	return pos;
}

/****************************************************
*		Compare the contents of jfm files
****************************************************/
int jfmcmp(char *pk1, char *pk2)
{
	int nt, lh1, lh2, ec, nw, nh, nd;

	if(get_int(pk1) != get_int(pk2))	/* id */
		return 1;
	nt = get_int(pk1);
	if(nt != get_int(pk2))
		return 2;

	pk1 += 2;						/* file length */
	lh1 = get_int(pk1);
	pk1 += 2;

	pk2 += 2;
	lh2 = get_int(pk2);
	pk2 += 2;

	ec = get_int(pk1);
	if(ec != get_int(pk2))
		return 4;

	nw = get_int(pk1);
	if(nw != get_int(pk2))
		return 5;

	nh = get_int(pk1);
	if(nh != get_int(pk2))
		return 6;

	nd = get_int(pk1);
	if(nd != get_int(pk2))
		return 7;

	return 
		memcmp(pk1 + ((2+lh1)<<2) + 2, pk2 + ((2+lh2)<<2) + 2, 
			(nt+ec+nw+nh+nd+1)<<2)?8:0;
}

/***********************************************
*	Main routine to Embed Fonts/Images
************************************************/
static int WriteETF(char *out_name, short *dpis, int count)
{
	int i, j, k, num_font, pos, num_ch, size, size0;
	int	hsize, type, c_type, hdpi, mx, mn;
	short int *fdx;
	char *name;
	FONT_INDEX *font_index;
	FONT_INDEX *f_index;
	FONT_INFO *font_info;
	ETF_INFO  *etf_info_pt;
//	CMTT_INFO *cm_ptr;
	ETF_IMAGE *im;
	FILE *fp, *fo;
	char dviadd[MAX_PATH];
	char tmp_name[MAX_PATH];
	char tmp2_name[MAX_PATH+2];
	char tmp3_name[MAX_PATH+1];
	char tmp4_name[MAX_PATH+2];
	char *arg[4];
	struct JFM_LINK {
		struct JFM_LINK *next;
		int		pos;
		int		size;
		char	data[];
	} *jl, *jl1, *jl_base;

#define	HTOP_SIZE	(8*sizeof(int))
#define	FILL		0x00

	SetPath(tmp_name, "^?\\dviout.$$$");
	fdx = (short int *)marea((etf_pt+1)*sizeof(short int));
	fdx[0] = num_font = etf_pt?0:-1;
	extra = 0;

	for(i = 1; i < etf_pt; i++){
		fdx[i] = num_font;
		k = 0;
		if(etf_info[i-1].font->font_type != etf_info[i].font->font_type){
			k = 1;
		}else if(etf_info[i].font->font_type == TT_FONT){
			if(strcmp(etf_info[i-1].font->ext.kdir->name, 
				etf_info[i].font->ext.kdir->name))
				k = 1;
		}else if(etf_info[i].font->font_type == WINTT_FONT ||
				 etf_info[i].font->font_type == WINJTT_FONT){
			if(strcmp(etf_info[i-1].font->n, etf_info[i].font->n))
				k = 1;
		}else if(strcmp(etf_info[i-1].font->name, etf_info[i].font->name))
			k = 1;
		if(k)
			num_font = ++fdx[i];
		else if(etf_info[i-1].code == etf_info[i].code)
			fdx[i] = -1;
	}

	if(!ArrangeETFFont(etf_info, fdx, etf_pt, num_font+1, etf_img.next)){
quit:	Free0(etf_info);
		Free(fdx);
		etf_info = NULL;
		etf_pt = etf_end = 0;
		return 0;
	}
	MessagePage(-1);
	DisplayMessage("Embedding");
	strcpy(tmp4_name, "+ ");
	SetPath(tmp4_name+2, "^?\\initial.par");
	if(!common_work[0])
		*tmp4_name = 0;
	else if(common_work[0] == 1)
		*tmp4_name = '-';
	else{
		fp = fopenf(tmp4_name+2, "wb");
		fprintf(fp, "%s", common_work);
		fclose(fp);
	}
	/* recount the number of fonts */
	num_font = 0;
	for(i = etf_pt - 1; i >= 0; i--){
		if(fdx[i] >= 0){
			num_font = fdx[i] + 1;
			break;
		}
	}
	if(!num_font){
		if(etf_img.next == NULL && !*tmp4_name)
			goto quit;
		tmp2_name[1] = 0;
		goto nof;
	}

	font_index = (FONT_INDEX *)marea(num_font*sizeof(FONT_INDEX));
	/* Mapping Table */

	jl_base = NULL;
	fp = fopenf(tmp_name, "wb");
	/* Font table */
	for(i = j = pos = type = 0; i < num_font; i++){
		while(fdx[j] < 0)
			j++;
		font_index[i].name = strlen(etf_info[j].font->n) + 1;
		c_type = font_index[i].type = etf_info[j].font->font_type;
		font_index[i].resol = (c_type == PK_FONT)?etf_info[j].font->sdpi:0;
		font_info = etf_info[j].font;

		num_ch = 0;

			/*******   		WINTT_FONT (tfm + WinAPI) 		*******/
			/*******	tfm_width in Code Table part  		*******/
			/*******		   No Glyph part				*******/
		if(c_type == WINTT_FONT){
			int last_code;

			font_index[i].Coffset = pos;
			for(last_code = -1; j < etf_pt && fdx[j] <= i; j++){
				if(fdx[j] < 0 || last_code == etf_info[j].code)
					continue;
				putint(last_code = etf_info[j].code, fp);
				putint(etf_info[j].tfm_width, fp);
				pos += 2*sizeof(int);
				num_ch++;
			}
			font_index[i].num = num_ch;
			goto skpg;
		}
								/* Open font file */
		if(c_type == TT_FONT){
			char path[MAX_PATH];

			sprintf(path, "%s.ttc", font_info->ext.kdir->name);
			if( (fo = fopenf(path, "rb")) == NULL){
				strcpy(path + strlen(path) - 3, "ttf");
				name = path;
				fo = fopenf(name, "rb");
			}
		}else
			fo = fopenf(name = font_info->name, "rb");
		if(fo == NULL)
			error(PROGRAM_STOP, "Cannot open %s", name);

		/******************    Write Glyph part   *******************/
		for(k = j; k < etf_pt && fdx[k] <= i; k++){
			if(fdx[k] < 0)
				continue;
			etf_info_pt = etf_info + k;
#if	!ETF_PACK
			if(c_type != PK_FONT){
				while(pos & 0x3){
					pos++;
					fputc(FILL, fp);
				}
			}
#endif
			size = size0 = etf_info[k].end - etf_info[k].top + 1;
			if(size < 0 || size > 0x20000){
				error(WARNING, 
					"Internal Error: abnormal size %d-%d in %s(code %d)",
					etf_info_pt->top, etf_info_pt->end, etf_info_pt->font->n, 
					etf_info_pt->code);
				etf_error = 1;
			}
					/***** Write PRE_GLYPH *****/
			switch(c_type){
				case CMTTF:
					putshort(etf_info_pt->lsb, fp);		// lsb
					putint(etf_info_pt->tfm_width, fp);	// TFM width
					pos += sizeof(short int) + sizeof(int);
					break;
				case PK_FONT:
					fputc(etf_info_pt->lsb, fp);			// flag_byte
					pos++;
					break;
				case VIRTUAL_FONT:
					putint(size, fp);					// glyph size
					putint(etf_info_pt->tfm_width, fp);	// TFM width
					pos += 2*sizeof(int);
					break;
				case WINJTT_FONT:
					font_index[i].Coffset = pos;
					size = 0;
					break;
				default:
					break;
			}
			etf_info_pt->lsb = pos;					// record position
			if(fo)
				fseek(fo, etf_info_pt->top, SEEK_SET);

					/*****	 Write Glyph	 *****/
			if(c_type != WINJTT_FONT){
				num_ch++;
				pos += size;
				while(size-- > 0)
					fputc(fgetc(fo), fp);			// copy glyph
			}else{
					/***  	WINJTT_FONT (jfm + WinAPI)	 ***/
				size = filelength(fileno(fo));
				jl1 = (struct JFM_LINK*)
					marea(size + 2*sizeof(int) + sizeof(struct JFM_LINK*));
				jl1->pos = pos;
				jl1->size = size;
				jl1->next = NULL;
				fread(jl1->data, size, 1, fo);
				if((jl = jl_base) != NULL){
					while(jl->next)
						jl = jl->next;
					jl->next = jl1;
				}else
					jl_base = jl1;
				for(jl = jl_base; jl != jl1;jl = jl->next){
#if 0
					if(jl->size == size
					  && !memcmp(jl->data, jl1->data, size))
#else
					if(!jfmcmp(jl->data, jl1->data))
#endif
					{
						font_index[i].Coffset = jl->pos;	// rewrite position
						Free(jl1);
						while(jl->next != jl1)
							jl = jl->next;
						jl->next = NULL;
						goto end_jl;
					}
				}
				fwrite(jl1->data, size, 1, fp);
				pos += size;
			}
end_jl:;
		}
		if(fo)
			fclose(fo);
		font_index[i].num = num_ch;

		if(c_type == WINJTT_FONT){
			for(; j < etf_pt && fdx[j] <= i; j++);
			goto skpg;
		}

		while(pos & 0x3){
			pos++;
			fputc(FILL, fp);
		}

		/*******************    Code Table part   *****************/
		font_index[i].Coffset = pos;
		k = j;
		for(; j < etf_pt && fdx[j] <= i; j++){
			if(fdx[j] < 0)
				continue;

			putint(etf_info[j].code, fp);		// code
			putint(etf_info[j].lsb, fp);		// offset
			pos += 2*sizeof(int);
		}
		switch(c_type){
			int preg;

			case PK_FONT:
				preg = 1;
				goto stp;

			case CMTTF:
				preg = 6;
				goto stp;

			case TT_FONT:
				preg = 0;
stp:			putint(0, fp);
				putint((preg << 24)+size0, fp);	// for the size of (last) glyph
				pos += 2*sizeof(int);
			default:
				break;
		};

		if(c_type == CMTTF || c_type == TT_FONT){	// record font filename
			char *s, *t;

			s = (c_type == CMTTF)?
				etf_info_pt->font->n:etf_info_pt->font->ext.kdir->name;
			for(t = s; *t; t++){
				if(*t == ':' || *t == '\\' || *t == '/')
					s = t+1;
				else if(IsJapanese() && issjis1(*t) && t[1])
					t++;
			}
			do{
				putc(*s, fp);
				pos++;
			}while(*s++);
		}
skpg:
		/* Glyph_Header */
		while(pos & 0x3){
			pos++;
			fputc(FILL, fp);
		}
			/****** 	Font Header part 	******/
					/* (top of) Hoffset */
		font_index[i].Hoffset = pos;

		switch(c_type){
			case(CMTTF):
#if	0
				if(font_info->pk == NULL)
					font_info->pk = load_pk(font_info->name, font_info->n);
				cm_ptr = (CMTT_INFO *)(font_info->pk + 4);
				putint(cm_ptr->unitsPerEm, fp);
				putint(0, fp);
				pos += 2*sizeof(int);
#else
				pos = 
					WriteECMHeader(etf_info + k, fdx + k, j-k, pos, fp);
				font_index[i].Hoffset = etf_info[k].lsb;

#endif
				type |= 1;
				break;

			case(TT_FONT):
				pos = 
					WriteETTHeader(etf_info + k, fdx + k, j-k, pos, fp);
				font_index[i].Hoffset = etf_info[k].lsb;
				type |= 2;
				break;

			case(VIRTUAL_FONT):
				type |= 0x8;
				pos += WriteVirtualETF(font_info, fp);
				break;

			case(PK_FONT):
				type |= 4;
				break;

			case(WINJTT_FONT):
				type |= 0x20;
				goto ckftt;

			case(WINTT_FONT):
				type |= 0x10;
ckftt:			name = check_ftt(font_info->n);
				if(font_info->n == name)
					name = "";
				do{
					fputc(*name, fp);
					pos++;
				}while(*name++);
				break;

			default:
				break;
		}

	}
	fclose(fp);
	if(jl_base){
		for(jl = jl_base; jl; jl = jl1){
			jl1 = jl->next;
			Free(jl);
		}
	}

	/*******   rewrite font_index  for fdx[j]  < -1 	********/
	if(extra)
		f_index = (FONT_INDEX *)marea((num_font+extra)*sizeof(FONT_INDEX));

	for(mn=-1, i = j = k = mx = 0; j < etf_pt; k++){
		while(fdx[j] == -1)
			j++;
		if(extra){
			f_index[k].name = strlen(etf_info[j].font->n) + 1;
			f_index[k].resol = font_index[i].resol;
			f_index[k].type = font_index[i].type;
			f_index[k].num = font_index[i].num;
			f_index[k].Coffset = font_index[i].Coffset;
			f_index[k].Hoffset = (fdx[j] >= 0)?
				font_index[i].Hoffset:etf_info[j].lsb;
		}
		while(++j < etf_pt){
			if(fdx[j] > mx){
				i = mx = fdx[j];
				break;
			}
			if(fdx[j] < mn){
				mn = fdx[j];
				break;
			}
			fdx[j] = -1;
		}
	}
	if(extra){
		Free(font_index);
		font_index = f_index;
		num_font += extra;
	}
	fo = fopenf(tmp_name, "rb");
	if(out_name)
		strcpy(tmp2_name+1, out_name);
	else
		SetPath(tmp2_name+1, "^?\\dviout.etf");
	fp = fopenf(tmp2_name+1, "wb");

	for(i = size = 0; i < num_font; i++)
		size += font_index[i].name;

	pos = size + HTOP_SIZE;

	if(pos & 1)
		pos++;

	if(count > 1){			/***** multi dvi *****/
		hdpi = pos | 0x8000;
		pos += 2*(count+1);
	}else
		hdpi = dpis[0];

	pos = (pos + 3)&~3;
	hsize = pos + num_font*sizeof(FONT_INDEX);

	/*************		write dviout.etf 		**************/
		/********** 		  Header		 ***********/
	fputc('E', fp);
	fputc('F', fp);
	fputc(ETF_SUBVER, fp);	/* version minor */
	fputc(ETF_VERSION, fp);	/* version major */
	putint(hsize + filelength(fileno(fo)), fp);		/* file length */
	putint(hdpi|(type<<16), fp);	/* dpi, type */
	putint(hsize, fp);		/* glyph base */
	putint(num_font, fp);	/* number of font */
	putint(pos, fp);		/* offset of font_table */
	putint(0, fp);			/* number of mapping fonts */
	putint(0, fp);			/* offset of mapping font */
	pos = HTOP_SIZE;

		/***** 	Font names 	*****/
	for(i = j = 0; i < num_font; ){
		while(fdx[j] == -1)
			j++;
		fprintf(fp, "%s%c", etf_info[j].font->n, 0);
		font_index[i++].name = pos;
		pos += strlen(etf_info[j++].font->n) + 1;
	}
	Free(fdx);
	if(pos & 1){
		pos++;
		fputc(FILL, fp);
	}

	if(count > 1){					/****	 multiple dpi ****/
		for(i = 0; i <= count; i++){
			fputc(dpis[i] & 0xff,fp);
			fputc(dpis[i] >> 8,fp);
			pos += 2;
		}
	}

	while(pos & 3){
		pos++;
		fputc(FILL, fp);
	}
			/*****		Font data		*****/
	for(i = 0; i < num_font; i++){
		putint(font_index[i].name, fp);
		putint(font_index[i].resol, fp);
		putint(font_index[i].type, fp);
		putint(font_index[i].num, fp);
		putint(font_index[i].Hoffset, fp);
		putint(font_index[i].Coffset, fp);
	}
	pos += num_font*sizeof(FONT_INDEX);

		/**********   	copy Glyph Part etc.		*********/
	while((i = fgetc(fo)) != EOF)
		fputc(i, fp);
	fclose(fo);
	fclose(fp);

	unlink(tmp_name);
	Free(font_index);
	if(pos!= hsize){
		error(WARNING, "Internal Error in Header Size(%x:%x)", pos, hsize);
		return 0;
	}
nof:
	if(out_name == NULL){
		GetModuleName(dviadd);
		i = strlen(dviadd);
		while(dviadd[i] != '\\' && dviadd[i] != ':'){
			if(--i < 0)
				break;
		}
		strcpy(dviadd + i + 1, "dviadd.exe");
		tmp2_name[0] = '+';
		arg[0] = dviadd;
		if(etf_img.next || *tmp4_name){		/* image files or initial.par */
			SetPath(tmp3_name+1, "^?\\tmp.par");
			tmp3_name[0] = '@';
			fo = fopenf(tmp3_name+1, "wt");
			if(tmp2_name[1])
				fprintf(fo, "+ %s\n", tmp2_name+1);
			for(im = etf_img.next; im; im = im->next)
				fprintf(fo, "%c %s\n", (im->flag)?'+':'-', im->image);
			fprintf(fo, tmp4_name);
			fclose(fo);
			arg[1] = tmp3_name;
		}else
			arg[1] = tmp2_name;
		arg[2] = current_name;
		arg[3] = NULL;
		if(!WinMinExecute(arg, 0, TRUE)){
			error(WARNING, "Cannot execute %s\n%s is created.", 
				dviadd, tmp2_name+1);
		}else{
			if(tmp2_name[1])
				unlink(tmp2_name+1);
		}
		if(etf_img.next || *tmp4_name)
			unlink(tmp3_name+1);
		if(*tmp4_name)
			unlink(tmp4_name+2);
	}
	return 1;
}

/**************************************************
*	Get font Metric of ETF and set PREAMBLE
*			called from getfont.c
***************************************************/
CMTT_INFO cmetf_info;

void etf_metrics(unsigned char **pk_ptr, FONT_INFO *font, int char_code, 
	PREAMBLE *preamble)
{
	int offset, lsb, num;
	int *tfw;
	double dotsize, tmp;

	glyph.IndexBase = cmetf_info.IndexBase = font->pk - etf_font;
	glyph.GlyphBase = cmetf_info.GlyphBase = etf_glyph - etf_font;
	if(font->etf_type == PK_FONT){
		offset = get_glyph_offset(-1, char_code);
		if(offset == EXCEPTION)
except:		error(FONT_MISMATCH, "Error in ETF-%d code %xH in %s(%d)", 
				font->font_type, char_code, font->n, font->dpi);
		*pk_ptr = etf_glyph + offset - 1;
		return;
	}
	if(font->etf_type == VIRTUAL_FONT){
		offset = get_glyph_offset(-1, char_code);
		if(offset == EXCEPTION)
			goto except;
		*pk_ptr = etf_glyph + offset;
		preamble->byte_width = GetInt(*pk_ptr - 8);
		preamble->tfm_width = mult20(GetInt(*pk_ptr - 4), font->size_para);
		preamble->width = preamble->height = preamble->pitch_offset
						= preamble->depth_offset = 1;
		return;
	}
	if(font->etf_type == WINTT_FONT){
		offset = get_glyph_offset(-2, char_code);
		if(offset == EXCEPTION)
			goto except;
		preamble->tfm_width = mult20(offset, font->size_para);
		return;
	}
	offset = get_glyph_offset(0, char_code);
	if(offset == EXCEPTION)
			goto except;
	cmtt_ptr = &cmetf_info;
	if(font->etf_type == TT_FONT){
		int tw;
		ETT_FONT *ett;

		ett = (ETT_FONT*)GetHoffset(font);
		tfw = (int *)ett;
		tw = ett->tfm_width;
		for(num = ett->extra; --num >= 0; ){
			if(*(tfw -= 2) <= char_code){
				if(*tfw == char_code)
					tw = *(tfw+1);
				break;
			}
		}
		preamble->tfm_width = mult20(tw, font->size_para);
		glyph.indexToLocFormat = 1;
		glyph.unitsPerEm = ett->unitsPerEm;
		cmtt_ptr->yMax = glyph.unitsPerEm + ett->yMin;
		cmtt_ptr->xMin = ett->xMin;
		goto skip;
	}
	tfw = (int *)GetHoffset(font);
	glyph.unitsPerEm = cmetf_info.unitsPerEm = *tfw;
	/* glyph のバウンダリより metrics を算出 */
	lsb = (short int)(buf[bp-6] + (buf[bp-5] << 8));
	preamble->tfm_width = mult20(GetInt(buf+bp-4), font->size_para);
	if(etf_version >= 3){
		num = tfw[1];
		while(--num >= 0){
			if(*(tfw -= 2) <= char_code){
				if(*tfw == char_code)
					preamble->tfm_width = mult20(tfw[1], font->size_para);
				break;
			}
		}
		
	}
	bp += 2;
	cmtt_ptr->xMin = (short int)read_n_byte(0, 2);
	cmtt_ptr->yMin = (short int)read_n_byte(0, 2);
	cmtt_ptr->xMax = (short int)read_n_byte(0, 2);
	cmtt_ptr->yMax = (short int)read_n_byte(0, 2);

#define CEIL(X)  (((X) > (int)(X)) ? ((int)(X) + 1) : ((int)(X)))
#define FLOOR(X) (((X) < (int)(X)) ? ((int)(X) - 1) : ((int)(X)))

	/* dotsize = TT font の座標系における 1 dot の大きさ */
	dotsize = (double)cmtt_ptr->unitsPerEm
			/ (double)sptopixel(font->size_para);
	tmp = (double)cmtt_ptr->xMin / dotsize;
	cmtt_ptr->xMin = FLOOR(tmp) * dotsize;
	tmp = (double)cmtt_ptr->xMax / dotsize;
	cmtt_ptr->xMax = CEIL(tmp) * dotsize;
	tmp = -(double)lsb / dotsize;
	preamble->pitch_offset = CEIL(tmp);
	preamble->width = (double)(cmtt_ptr->xMax-cmtt_ptr->xMin) / dotsize + 0.5;

	dotsize = (double)cmtt_ptr->unitsPerEm
			/ (double)vtopixel(font->size_para);
	tmp = (double)cmtt_ptr->yMin / dotsize;
	cmtt_ptr->yMin = FLOOR(tmp) * dotsize;
	tmp = (double)cmtt_ptr->yMax / dotsize;
	cmtt_ptr->yMax = CEIL(tmp) * dotsize;
	preamble->depth_offset = (double)cmtt_ptr->yMax / dotsize + 0.5;
	preamble->height = (double)(cmtt_ptr->yMax-cmtt_ptr->yMin) / dotsize + 0.5;

skip:	/* glyph データ先頭に seek する */
	bp = glyph.GlyphBase + offset;
}

/***************************************************
*	Delete Embedded Fonts from the current DVI file
***************************************************/
BOOL DeleteETF(int mode)
{
	int i;
	char dviadd[MAX_PATH];
	char *arg[4];

	GetModuleName(dviadd);
	i = strlen(dviadd);
	while(dviadd[i] != '\\' && dviadd[i] != ':'){
		if(--i < 0)
			break;
	}
	strcpy(dviadd + i + 1, "dviadd.exe");
	arg[0] = dviadd;
	arg[1] = (mode==1)?"d":"-dviout.etf";
	arg[2] = current_name;
	arg[3] = NULL;
	if(!WinMinExecute(arg, 0, TRUE)){
		error(WARNING, "Cannot execute %s.", dviadd);
		return FALSE;
	}
	return TRUE;
}

/**************************************
*	A routine use only from  MakeETF()
**************************************/
static void FreeETFLocal(FONT_INFO *font)
{
	FONT_INFO *finfo_pt;
	FONT_INFO *tmp;

	for(finfo_pt = font; finfo_pt; ){
		tmp = finfo_pt;
		finfo_pt = finfo_pt->next_font;
		Free0(tmp->name);
		Free0(tmp);
	}
}

/*********************************************
*	Main routine to Embed Fonts
**********************************************/
BOOL MakeETF(void)
{
#define	MAX_DPIS	0x100
	int i, j, k, m, page, total, c_page, org_dpi;
	char *str_dpi;
	FONT_INFO *tmp;
	FONT_INFO *finfo_top;
	FONT_INFO *finfo_pt;
	short dpis[MAX_DPIS];

	finfo_top = NULL;
	etf_error = 0;
	ClearFont();

	c_page = GetCurrentPage();
	total = GetTotalPage();

		/* analyze dpi for PK fonts */
	str_dpi = f_make_dpi;
	org_dpi = GetXDpi();
	for(i = 0; i < MAX_DPIS-1; i++){
		dpis[i] = (str_dpi)?atoi(str_dpi):0;
		if(!dpis[i]){
			if(str_dpi == f_make_dpi){
				dpis[i++] = org_dpi;
				dpis[i] = 0;
			}
			break;
		}
		while(*str_dpi >= '0' && *str_dpi <= '9')
			str_dpi++;
		while((*str_dpi >= 0x20 && *str_dpi <= 0x2f) || *str_dpi == '\t')
			str_dpi++;
		if(*str_dpi < '0' || *str_dpi > '9'){
			i++;
			break;
		}
	}
	dpis[i] = 0;
	Free0(f_make_dpi);
	f_make_dpi = NULL;
	if(  !f_make_pketf && !f_make_etf && !f_make_jttetf && !f_make_vfetf
	  && !f_make_mapetf && !f_make_wjtetf && !f_make_imgetf)
		goto stp;

		/* scanning pages to correct Font/Image data */
	for(k = 0, j = i-1; j >= 0; j--){
		BOOL f_etf, f_jttetf, f_vfetf, f_mapetf, f_imgetf, f_wjtetf, f_use;

		if(j == i-1){
			f_use    = f_use_etf;
			f_etf    = f_make_etf;
			f_jttetf = f_make_jttetf;
			f_vfetf  = f_make_vfetf;
			f_mapetf = f_make_mapetf;
			f_wjtetf = f_make_wjtetf;
			f_imgetf = f_make_imgetf;
		}
		if(j == 0 || !f_make_pketf){
			f_make_etf    = f_etf;
			f_make_jttetf = f_jttetf;
			f_make_vfetf  = f_vfetf;
			f_make_mapetf = f_mapetf;
			f_make_wjtetf = f_wjtetf;
			f_make_imgetf = f_imgetf;
		}else
			f_make_etf = f_make_jttetf = f_make_vfetf = f_make_mapetf = 
			f_make_wjtetf = f_make_imgetf = FALSE;

		SetParaInt("dpi", dpis[j]);
		f_use_etf = FALSE;
		ClearFont();
		FreeETF();
		for(page = 1; page <= total; page++){
			ChgPage(page);
			MessagePage(page);
			ExpandPage0();
			if(etf_error)
				goto stp; 
		}
		f_use_etf = f_use;

		if(etf_pt){
		/* the following is for multiple dpi since font data is cleared */
			qsort(etf_info + k, etf_pt - k, sizeof(ETF_INFO), (COMP)eft_comp);
			for(m = k; 
			  m < etf_pt && etf_info[m].font->font_type == PK_FONT; m++){
				if(!m || 
				  strcmp(etf_info[m].font->name, etf_info[m-1].font->name)){
					tmp = (FONT_INFO *)marea(sizeof(FONT_INFO));
					memcpy(tmp, etf_info[m].font, sizeof(FONT_INFO));
					tmp->next_font = NULL;
					tmp->name = strdup(etf_info[m].font->name);
					tmp->sdpi |= (dpis[j]<<16);
					if(!finfo_top)
						finfo_top = tmp;
					else
						finfo_pt->next_font = tmp;
					etf_info[m].font = finfo_pt = tmp;
				}else
					etf_info[m].font = etf_info[m-1].font;
			}
		}
		if(!f_make_pketf)
			break;
		k = etf_pt;
	}
stp:
	ClearFont();
	f_make_pketf = f_make_etf = f_make_jttetf = f_make_vfetf = f_make_mapetf
		= f_make_wjtetf = f_make_imgetf = FALSE;
	SetParaInt("dpi", org_dpi);
	MessagePage(0);

	if(etf_error){
		if(etf_error & EXCEPTION){
			error(WARNING, 
				"Cannot find tfm file for %s\n"
				"Indicate it in -TEXFONT: (ex. ^r\\tfm\\\\)\n"
				"Abort embedding.",
				etf_info[etf_error&0xffff].font->name);
		}
quit:	etf_error = 1;
	}else{
wetf:	WriteETF(NULL, dpis, i);
		MessagePage(0);
	}
	FreeETFLocal(finfo_top);
	FreeETFImage(etf_img.next);
	Free0(etf_info);
	etf_info = NULL;
	etf_img.next = NULL;
	etf_pt = etf_end = 0;
	ChgPage(c_page);
	SetStartPage(c_page);
	return etf_error?FALSE:TRUE;
}

/************************************************
*		Display Information of Embedded Fonts
************************************************/
BOOL DisplayETF(void)
{
	int i, size, total;
	char *msg;

	if(etf_font == NULL)
		return FALSE;

	for(i = total = 0; i < etf_max_idx; i++){
		error(C_MSG, "%s\t", msg = etf_font + etf_idx[i].name);
		if(strlen(msg) < 8)
			error(C_MSG, "\t");
		switch(etf_idx[i].type){
			case PK_FONT:
				msg = "PK";
				break;
			case CMTTF:
				msg = "TT";
				break;
			case VIRTUAL_FONT:
				msg = "Virtual";
				break;
			case WINTT_FONT:
				msg = "TFM";
				break;
			case TT_FONT:
				msg = "JTT";
				break;
			case WINJTT_FONT:
				msg = "JFM";
				break;
			default:
				msg = "";
		}
		size = etf_idx[i].Hoffset;
		if(i)
			size -= etf_idx[i-1].Hoffset;
		error(C_MSG, "%3d characters  %7d byte (%s", 
			etf_idx[i].num, size, msg);
		if(etf_idx[i].resol)
			error(C_MSG, ",%4d/%ddpi)\n", etf_idx[i].resol & 0xffff,
				etf_idx[i].resol>>16);
		else
			error(C_MSG, ")\n");
		if(i == 0 ||  etf_idx[i].Coffset != etf_idx[i-1].Coffset)
			total += etf_idx[i].num;
	}
	error(C_MSG, " --- total ---\n%3d fonts    %6d characters %8d byte (",
		etf_max_idx, total, etf_size);
	size = etf_font[8] + (etf_font[9]<<8);
	if(size & 0x8000){
		i = size & 0x7fff;
		while((size = etf_font[i] + (etf_font[i+1]<<8)) != 0){
			i += 2;
			error(C_MSG, "%d ", size);
		}
	}else
		error(C_MSG, "%d ", size);
	error(C_MSG, "dpi)\n");
	error(DATATITLE, "Embeded Fonts");
	return TRUE;
}
#endif
