/* TTFB.C Created by Yidao CAI on JULY-1-94
   Last modified on May 8, 2001

 * Jan. 20, 2001: test for using instructions (& CVT, PREP), add non-TTF
   detection
 * April 28, 2000: fix a "bug" in complex glyph handling
 * May 14, 1999: add composite glyph support, use unicode font via code
   mapping
 * May 12, 1999: add format 4 cmap code mapping
 * Sept. 17, 1998: use new TTF fonts supplied by Honda Siew, and add
   interface for cnprint.
 * July 27, 1994: basic things done, but glyph part not working properly
   for NTU fonts, may be due to non-standard design
 * TTFGET.C, an experimental program to get TTF glyph data
   This program benefited from the TTF2PS.C (Lin YawJen & Liang Shing Ng)
*/
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
/*#include <alloc.h>*/

/* for CNPRINT parameter passing */
extern int  mx, my;
extern FILE *out, *errout;
extern FILE *Rfopen(char *, char *);
extern void putBitmap85(unsigned char *, int);
void putBitmap85_(unsigned char *, int);
extern int UnicodeTTF; /* TTF font uses unicode encoding, may need mapping */
extern void MemExit(void);

short xmin, ymin;
int     xmax, ymax;     /* gluph bounding box */
int	my_xmin, my_ymin, my_xmax, my_ymax;
int	scl=1;		/* scale if bounding box too small, < 1000 */
int     LongFormat;     /* indextoLocFormat */

struct TableEntry {
	char name[5];
	unsigned long offset, len;
} cmap, glyf, head, loca, maxp, name, cvt, prep;

/* CVT */
short	*CVT_table;
int	CVT_tablelen;
unsigned char	*PREP_table;
int	PREP_tablelen;

int	CMAP_Format;

/* for CMAP format 2 */
unsigned int SubHeadKey[256];
struct SubHD {
       unsigned short code1, N2bytes, idOffset;
       short idDelta;
} *SubHeader = NULL;

/* for CMAP format 4 */
int	CMAP4_nseg;
struct SegHD {
       unsigned short start, end, idOffset;
       short idDelta;
} *SegHeader = NULL;


/* glyf data: treat as if they are in a struct */
int	glyf_nctours, glyf_npts;	/* # of contours, total points */
short	*glyf_x, *glyf_y;
unsigned char *glyf_flag;
unsigned short *glyf_ctour_endpts;
unsigned short *glyf_index_array;

short point[2048], op[2048];
int   pidx, oidx;

/* for composite glyph */
#define ARG_1_AND_2_ARE_WORDS	0x0001
#define ARGS_ARE_XY_VALUES 	0x0002
#define XY_BOUND_TO_GRID	0x0004
#define HAVE_A_SCALE		0x0008
#define MORE_COMPONENTS		0x0020
#define HAVE_XY_SCALES		0x0040
#define HAVE_A_TWO_BY_TWO	0x0080
#define HAVE_INSTRUCTIONS	0x0100
#define USE_MY_METRICS		0x0200
/* transform or translate component glyph */
short	g_xoff, g_yoff;
float	g_xx, g_xy, g_yx, g_yy;

/* maxp */
unsigned short Nglyphs, max_pts, max_ctours,
	max_comp_pts, max_comp_ctours, max_depth;

int get_glyf(FILE *, unsigned short);
unsigned short FontIndex(unsigned char, unsigned char);
void load_cmap(FILE *);
void load_cvt(FILE *);
void load_prep(FILE *);
void clear_data();
void uappend_fill85();
void PSLineto(short, short);
void PSCurveto(short, short, int, int);
FILE *TTFopen_init(char *);
void TTFgen_PSproc(FILE *, unsigned int, unsigned int);

unsigned short get2(FILE *fp)
{
	unsigned char c1 = fgetc(fp);
	return ( ( (unsigned short) c1 << 8) + (unsigned char) fgetc(fp) );
}

unsigned long get4(FILE *fp)
{
	unsigned long l = get2(fp);
	return l*65536L + get2(fp);
}


int GetTable(FILE *fp)
{
	char s[5];
	int j, Ntable;
	int n;
	struct TableEntry tmp, *a;

	fseek(fp, 4L, 0);
	Ntable = get2(fp);
	fseek(fp, 12L, 0);
	n = (Ntable > 50) ? 50 : Ntable;
 	cmap.name[0]='\0';
	for (j = 0; j < n; j++) {
		fread(s, 1, 4, fp);
		s[4] = 0;
		if (strcmp(s, "cmap")==0) a = &cmap;
		else if (strcmp(s, "loca")==0) a = &loca;
		else if (strcmp(s, "glyf")==0) a = &glyf;
		else if (strcmp(s, "head")==0) a = &head;
		else if (strcmp(s, "maxp")==0) a = &maxp;
		else if (strcmp(s, "name")==0) a = &name;
		else if (strcmp(s, "cvt ")==0) a = &cvt;
		else if (strcmp(s, "prep")==0) a = &prep;
		else a = &tmp;
		strcpy(a->name, s);
		get4(fp); /*** skip checksum ***/
		a->offset = get4(fp);
		a->len = get4(fp);
	}

/* cmap is a required table. if not present, then this is not a TTF */
 	return (cmap.name[0]=='\0')? 0:1;
}

void load_prep(FILE *fp)
{
	unsigned int j, k;

	fseek(fp, prep.offset, 0);
	PREP_tablelen = prep.len;
	PREP_table = (unsigned char *)
		calloc(sizeof(unsigned char), PREP_tablelen+1);
	if (PREP_table==NULL) MemExit();
	for (j=0; j<PREP_tablelen; j++) {
		PREP_table[j] = (unsigned char) fgetc(fp);
	}

}

void load_cvt(FILE *fp)
{
	unsigned int j, k;

	fseek(fp, cvt.offset, 0);
	CVT_tablelen = cvt.len/2;
	CVT_table = (short *) calloc(sizeof(short), CVT_tablelen+1);
	if (CVT_table==NULL) MemExit();
	for (j=0; j<CVT_tablelen; j++) {
		CVT_table[j] = get2(fp);
	}

}

void load_cmap(FILE *fp)
{
	unsigned int NumEncTable;
	struct EncTable {
		unsigned int PlatfmID;
		unsigned int PlatfmEncID;
		long offset;
	} *EncTables;
	unsigned int j, k, format, len, Nbyte1 = 0;
	int	nseg;

	fseek(fp, cmap.offset+2, 0); /* +2, skip table version */
	NumEncTable = get2(fp);
	EncTables = (struct EncTable *)
		calloc(sizeof(struct EncTable), NumEncTable);
	if (EncTables==NULL) MemExit();
	for (j=0; j<NumEncTable; j++) {
		EncTables[j].PlatfmID = get2(fp);
		EncTables[j].PlatfmEncID = get2(fp);
		EncTables[j].offset = get4(fp);
	}

/* we have two constraints:
 *   a. mapping format must be 2 or 4;
 *   b. languages must match.
 * if we get a UGL (unicode) (platformID=3, platformspEncId=1), or
 * an ISO 10646 (2, 1), we can handle everything
 * otherwise we have to assume input codes match font encoding
 */

	for (j=0; j<NumEncTable; j++) {
	    fseek(fp, cmap.offset+EncTables[j].offset, 0);
	    format = get2(fp);

	/* either format 2 or 4 will be good for CJK, use the first one got */
	    if (format != 2 && format != 4) continue;

	    if (EncTables[j].PlatfmID==3 && EncTables[j].PlatfmEncID==1
		|| EncTables[j].PlatfmID==2 && EncTables[j].PlatfmEncID==1)
			UnicodeTTF=1;

	/* format 2: use subheaders, each encodes upto 256 chars */
	    if (format==2) {
		len = get2(fp);
		get2(fp);       /* skip version */
		for (k=0; k<256; k++) {
			SubHeadKey[k] = get2(fp)/8;
			if (SubHeadKey[k] > Nbyte1) Nbyte1 = SubHeadKey[k];
		}

		SubHeader = (struct SubHD *)
			calloc(sizeof(struct SubHD), ++Nbyte1); /* or Nbyte1? */
		if (SubHeader==NULL) MemExit();
		for (k=0; k<Nbyte1; k++) {
			SubHeader[k].code1 = get2(fp);
			SubHeader[k].N2bytes = get2(fp);
			SubHeader[k].idDelta =  get2(fp);
			SubHeader[k].idOffset =  get2(fp) - (Nbyte1-k-1)*8-2;
		}
		/* 6: format, length, version;
			256*2: subArrayKey; Nbyte1*8: subHeaders */
		len -= 6+2*256+Nbyte1*8;
	    }

	/* format 4: MS, use segments, each may contain 1 to 65### chars */
	    else if (format==4) {
		len = get2(fp);
		get2(fp);       /* skip version */
		nseg = get2(fp); nseg /= 2; /* segCountX2 */
		get2(fp);	/* searchRange */
		get2(fp);	/* entrySelector */
		get2(fp);	/* rangeShift */

		SegHeader = (struct SegHD *)
			calloc(sizeof(struct SegHD), nseg+1);
		if (SegHeader==NULL) MemExit();
		for (k=0; k<nseg; k++) SegHeader[k].end = get2(fp);
		get2(fp);
		for (k=0; k<nseg; k++) SegHeader[k].start = get2(fp);
		for (k=0; k<nseg; k++) SegHeader[k].idDelta = get2(fp);
		for (k=0; k<nseg; k++) SegHeader[k].idOffset = get2(fp);
		CMAP4_nseg = nseg;
		len -= 16L + 8L * nseg;
	    }
	    len /= 2;
	    glyf_index_array = NULL;
	    if (len > 0) {
		glyf_index_array = (unsigned short *)
			calloc(sizeof(unsigned short), len);
		if (glyf_index_array==NULL) MemExit();
		for (k=0; k<len; k++) glyf_index_array[k] = get2(fp);
	    }
	    break;
	}
	CMAP_Format = format;
	free(EncTables);

	if (SubHeader==NULL && SegHeader==NULL) {
		fprintf(errout, "TTF CMAP: format 2 or 4 mapping not found\n");
		exit(-1);
	}
}

void GetMaxP(FILE *fp)
{
	fseek(fp, maxp.offset+4L, 0); /* skip table version */
	Nglyphs = get2(fp);
	max_pts = get2(fp);
	max_ctours = get2(fp);
	max_comp_pts = get2(fp);
	max_comp_ctours = get2(fp);
	get2(fp); get2(fp);
	get2(fp); get2(fp);
	get2(fp); get2(fp);
	get2(fp); get2(fp);
	max_depth = get2(fp);
}

void GetBoundingBox(FILE *fp) /* get glyph bounding box */
{
	fseek(fp, head.offset+36L, 0);
	xmin = (short) get2(fp);
	ymin = (short) get2(fp);
	xmax = (short) get2(fp) - xmin;
	ymax = (short) get2(fp) - ymin;
	mx=xmax; my=ymax;  /* for CNPRINT */
	if (xmax < 1000) {
		scl=4;
		mx *= scl; my *= scl;
	}

}

int GetIndexToLocFormat(FILE *fp)
{
	fseek(fp, head.offset+50L, 0);
	return (int) get2(fp);
}

int GetUnitsPerEm(FILE *fp)
{
	fseek(fp, head.offset+18L, 0);
	return get2(fp);
}

long LocalOffset(FILE *fp, int index)
/* offset to locations of glyphs re. beginning of glyphData table */
{
	long off;
	fseek(fp, loca.offset + index * ((LongFormat)? 4L:2L), 0);
	if (LongFormat) off = get4(fp);
	else off = 2 * (long) get2(fp);
	return off;
}

int GetCharContours(FILE *fp, unsigned short char_idx)
{
	short	i;
	unsigned short j;
	unsigned char c, ct;
	long	loff;

	loff = LocalOffset(fp, char_idx);
	fseek(fp, glyf.offset + loff, 0);
	glyf_nctours = (short) get2(fp);
	if (glyf_nctours < 0) return 0;	/* composite glyph */

/* skip glyf boundingbox */
	get2(fp); get2(fp); get2(fp); get2(fp);

	glyf_ctour_endpts = (unsigned short *)
		calloc(sizeof(unsigned short), glyf_nctours);
	if (glyf_ctour_endpts==NULL) MemExit();

/* if (glyf_nctours > 0) */
	for (i = 0; i < glyf_nctours; i++)
		glyf_ctour_endpts[i] = get2(fp);
	glyf_npts = glyf_ctour_endpts[glyf_nctours-1] + 1;
	j = get2(fp);		/* # of instructions */
	while (j--) getc(fp);	/* ? skip instructions */

	glyf_flag = (unsigned char *) calloc(sizeof(unsigned char), glyf_npts);
	if (glyf_flag==NULL) MemExit();
	glyf_x = (short *) calloc(sizeof(short), glyf_npts);
	if (glyf_x==NULL) MemExit();
	glyf_y = (short *) calloc(sizeof(short), glyf_npts);
	if (glyf_y==NULL) MemExit();

/* flags */
	for (j = 0; j < glyf_npts;) {
		glyf_flag[j++] = c = getc(fp);
		if (c&8) {		/* repeat */
			ct = getc(fp);
			while (ct--) glyf_flag[j++] = c;
		}
	}

/* x coordinates */
	for (j = 0; j < glyf_npts; j++) {
		if (glyf_flag[j] & 2) {
			c = getc(fp);
			glyf_x[j] = (glyf_flag[j] & 0x10)?
				((short) c) : (-1 * (short) c);
		}
		else if (glyf_flag[j] & 0x10) glyf_x[j] = 0;
		else glyf_x[j] = (short) get2(fp);
	}

/* y coordinates */
	for (j = 0; j < glyf_npts; j++) {
		if (glyf_flag[j] & 4) {
			c = getc(fp);
			glyf_y[j] = (glyf_flag[j] & 0x20)?
				((short) c) : (-1 * (short) c);
		}
		else if (glyf_flag[j] & 0x20) glyf_y[j] = 0;
		else glyf_y[j] = (short) get2(fp);
	}

/* x, y coordinate is always relative to previous one */
	for (j = 1; j < glyf_npts; j++) {
		glyf_x[j] += glyf_x[j-1];
		glyf_y[j] += glyf_y[j-1];
	}

	for (j = 0; j < glyf_npts; j++) {
		glyf_x[j] = ((long)(glyf_x[j] - xmin));
		glyf_y[j] = ((long)(glyf_y[j] - ymin));
	/* res x res, 1/4 precision, ** must shift coor before scale */
		/*glyf_x[j] = (((long)(glyf_x[j]-xmin))*res/(EM/4))-2;
		glyf_y[j] = (((long)(glyf_y[j]-ymin))*res/(EM/4))-2; */
	}
	return 1;
}

short RangeCheck(short i)
{
	if (i < 0) i = 0;
	return i;
}

void BuildGlyph()
{
	int i, j, start_offpt, end_offpt, fst;

/* first set ufill bounding box: no harm to set it bigger than needed */
	point[pidx++] = 0;
	point[pidx++] = 0;
	point[pidx++] = 1248;  /* xmax + 200 */
	point[pidx++] = 1248;  /* ymax + 200 */
	op[oidx++] = 0;

	for (i = 0, j = 0; i < glyf_nctours; i++) {
	    fst = j;
		/* PSMoveto(glyf_x[j], glyf_y[j]); */
	    point[pidx++] = RangeCheck(glyf_x[j]);
	    point[pidx++] = RangeCheck(glyf_y[j]);
	    op[oidx++] = 1;

	    start_offpt = 0;
	    for (j++; j <= glyf_ctour_endpts[i]; j++) {
		if (!(glyf_flag[j]&1)) { /*Off curve*/
		    if (!start_offpt) {
			start_offpt = end_offpt = j;
		    }
		    else end_offpt++;
		}
		else { /*On Curve*/
		    if (start_offpt) {
			PSCurveto(glyf_x[j], glyf_y[j], start_offpt, end_offpt);
			start_offpt = 0;
		    }
		    else PSLineto(glyf_x[j], glyf_y[j]);
		}
	    }
	    if (start_offpt)
		PSCurveto(glyf_x[fst], glyf_y[fst], start_offpt, end_offpt);
	    else PSLineto(glyf_x[fst], glyf_y[fst]);
	}
	op[oidx++] = 10; /* closepath */
}

void PSLineto(short x, short y)
{
	point[pidx++] = RangeCheck(x);
	point[pidx++] = RangeCheck(y);
	op[oidx++] = 3;
}

void PSCurveto(short x, short y, int s, int t)
{
	int N, i;
	double sx[3], sy[3], cx[4], cy[4];

	N = t-s+2;
	for (i=0; i<N-1; i++) {
	    sx[0] = i==0?glyf_x[s-1]:(glyf_x[i+s]+glyf_x[i+s-1])/2;
	    sy[0] = i==0?glyf_y[s-1]:(glyf_y[i+s]+glyf_y[i+s-1])/2;
	    sx[1] = glyf_x[s+i];
	    sy[1] = glyf_y[s+i];
	    sx[2] = i==N-2?x:(glyf_x[s+i]+glyf_x[s+i+1])/2;
	    sy[2] = i==N-2?y:(glyf_y[s+i]+glyf_y[s+i+1])/2;
	    cx[3] = sx[2];
	    cy[3] = sy[2];
	    cx[1] = (2*sx[1]+sx[0])/3;
	    cy[1] = (2*sy[1]+sy[0])/3;
	    cx[2] = (sx[2]+2*sx[1])/3;
	    cy[2] = (sy[2]+2*sy[1])/3;

	    point[pidx++] = RangeCheck((short)cx[1]);
	    point[pidx++] = RangeCheck((short)cy[1]);
	    point[pidx++] = RangeCheck((short)cx[2]);
	    point[pidx++] = RangeCheck((short)cy[2]);
	    point[pidx++] = RangeCheck((short)cx[3]);
	    point[pidx++] = RangeCheck((short)cy[3]);
	    op[oidx++] = 5;
	}
}

void clear_data()
{
	free(glyf_ctour_endpts);
	free(glyf_flag);
	free(glyf_x);
	free(glyf_y);
}


FILE *TTFopen_init(char *ttfname)
{
	FILE	*fpTTF;
	if((fpTTF = Rfopen(ttfname, "rb")) == NULL) {
		fprintf(errout, "TTF file not found --> %s\n", ttfname);
		exit(0);
	}
 	if (!GetTable(fpTTF)) {
 		fprintf(errout, "%s is not a true type font file.\n", ttfname);
 		fclose(fpTTF);
 		return NULL;
 	}
	GetMaxP(fpTTF);
/*
	load_cvt(fpTTF);
	load_prep(fpTTF);
*/
	LongFormat = GetIndexToLocFormat(fpTTF);
	load_cmap(fpTTF);
	GetBoundingBox(fpTTF); /* get glyph bounding box */
	return fpTTF;
}

void TTFclose(FILE *fp)
{
	fclose(fp);
	free(glyf_index_array);
	if (CMAP_Format==2) free(SubHeader);
	else if (CMAP_Format==4) free(SegHeader);
}

void uappend_fill85()
/* use ASCII base-85: <~ and ~>, level 2 only */
{
	int     i, j, count;
	unsigned char a[4100];

	fprintf(out, "{<");
	a[0] = (unsigned char) 149;
	a[1] = (unsigned char) 32;
	a[2] = (unsigned char) (pidx/256);
	a[3] = (unsigned char) (pidx%256);
	for (i=0; i<pidx; i++) {
		a[i*2+4] = (unsigned char) (point[i]/256);
		a[i*2+5] = (unsigned char) (point[i]%256);
	}
	putBitmap85(a, pidx*2+4);
	fprintf(out, ">\n<");

	count = 1;
	j=0;
	for (i=0; i<oidx-1; i++) {
	    if (op[i] == op[i+1]) count++;
	    else {
		if (count == 1) a[j++] = op[i];
		else {
			a[j++] = count+32; a[j++] = op[i];
		}
		count = 1;
	    }
	}
	a[j++] = op[oidx-1];  /* closepath */
	putBitmap85(a, j);
	fprintf(out, ">}");
}


unsigned short FontIndex(unsigned char c1, unsigned char c2)
/* c1, c2: high and low bytes of a HanZi char */
{
	unsigned short idx, ridx;
	unsigned short code;
	struct SegHD seghd;
	int	j;

	if (CMAP_Format==2) {
	    idx = SubHeadKey[c1];	/* value of Byte 1 */
	    if (idx==0) ridx=glyf_index_array[c1];
	    else {
		if ((short) c2 > SubHeader[idx].N2bytes + SubHeader[idx].code1)
			return 0; /* Error */
		ridx = SubHeader[idx].idDelta;
		ridx += glyf_index_array[SubHeader[idx].idOffset/2 +
		       (c2 - SubHeader[idx].code1)];
	    }
	}
	else if (CMAP_Format==4) {
	    code = (unsigned short) (c1*256 + c2);
	    for (j=0; j<CMAP4_nseg; j++ )
		if (code <= SegHeader[j].end) break;
		/* last endCount should be 0xFFFF, but an extra safety */
	    if (j >= CMAP4_nseg) return 0;
	    seghd = SegHeader[j];
	    if (code < seghd.start) return 0; /* unlikely */
	    if (seghd.idOffset == 0)
		ridx = (code + seghd.idDelta) & 0xFFFF;
	    else {
		/* ****** !!! this part may be wrong !!! ******* */
		idx = seghd.idOffset / 2 + (code - seghd.start)
			- (CMAP4_nseg - j);
		if (glyf_index_array[idx] == 0 ) return 0;
		else ridx = (glyf_index_array[idx] + seghd.idDelta) & 0xFFFF;
    	    }
	}

	return ridx;
}


static float f2dot14 (short y)
{
    return (y >> 14) + ((y & 0x3fff) / 16384.0);
	/*return (y << 2);*/
}

void TTFgen_PSproc(FILE *fp, unsigned int c1, unsigned int c2)
/*
 * from TTF file, generate the PS procedure for individual char
 * now handle composite glyph
 */
{
	unsigned short   cidx = FontIndex(c1, c2);
	short	ncontours;
	unsigned short flag, glyphindex, xscale, yscale, scale01, scale10;
	short	arg1, arg2;
	float	matrix[4];
	long	lcoff;
	int	j, k;
	long	m;
	unsigned short ninstr;

	pidx = oidx = 0; /* idx must reset after each glyf */
	lcoff = glyf.offset + LocalOffset(fp, cidx);
	fseek(fp, lcoff, 0);
	glyf_nctours = (short) get2(fp);

        if (glyf_nctours >= 0) {
		g_xoff = g_yoff = 0;
		g_xx = g_yy = 1.0;
		g_xy = g_yx = 0.0;
        	get_glyf(fp, cidx);
		BuildGlyph();
		uappend_fill85();
		clear_data();
        }
	else if (glyf_nctours < 0) {	/* composite glyph */
	    get2(fp); get2(fp);
	    get2(fp); get2(fp); /* skip glyf boundingbox */
	    lcoff += 10L;
	    k=0;
            do {
		g_xoff = g_yoff = 0;
		g_xx = g_yy = 1.0;
		g_xy = g_yx = 0.0;
		if (k++ > 0) {
			fprintf(out, "U\n");
			pidx = oidx = 0;
		}
		fseek(fp, lcoff, 0);
                flag = get2(fp);
                glyphindex = get2(fp);
		lcoff += 4L;
                if (flag & ARG_1_AND_2_ARE_WORDS) {
                    arg1 = (short) get2(fp);
                    arg2 = (short) get2(fp);
		    lcoff += 4L;
                } else {
                    m = get2(fp);
		    lcoff += 2L;
		    arg1 = (char) (m >> 8);
		    arg2 = (char) (m & 0xFF);
                }
                matrix[1] = matrix[2] = 0.0;

                if (flag & USE_MY_METRICS) {
			;
		}
                if (flag & XY_BOUND_TO_GRID) {
			;
		}
                if (flag & HAVE_A_SCALE) {
                    matrix[0] = matrix[3] = f2dot14((short) get2(fp));
		    lcoff += 2L;
                }
                else if (flag & HAVE_XY_SCALES) {
                    matrix[0] = f2dot14((short) get2(fp));
                    matrix[3] = f2dot14((short) get2(fp));
		    lcoff += 4L;
                }
                else if (flag & HAVE_A_TWO_BY_TWO) {
                    matrix[0] = f2dot14((short) get2(fp));
                    matrix[1] = f2dot14((short) get2(fp));
                    matrix[2] = f2dot14((short) get2(fp));
                    matrix[3] = f2dot14((short) get2(fp));
		    lcoff += 8L;
                }
		else {
                    matrix[0] = matrix[3] = 1.0;
                }
		g_xoff = arg1;
		g_yoff = arg2;
		g_xx = matrix[0];
		g_xy = matrix[1];
		g_yx = matrix[2];
		g_yy = matrix[3];
        	get_glyf(fp, glyphindex);
		BuildGlyph();
	        uappend_fill85();
		clear_data();
            } while (flag & MORE_COMPONENTS);
	}
}

int get_glyf(FILE *fp, unsigned short char_idx)
{
	short	i;
	unsigned short j;
	unsigned char c, ct;
	long	loff;
	float	x, y;

	loff = LocalOffset(fp, char_idx);
	fseek(fp, glyf.offset + loff, 0);
	glyf_nctours = (short) get2(fp);
	if (glyf_nctours < 0) {
		fprintf(stderr, "glyph component is a composite glyph: exit\n");
		return 0;	/* composite glyph */
	}

/* skip glyf boundingbox */
	/*get2(fp); get2(fp); get2(fp); get2(fp);*/
	    my_xmin=(short)get2(fp);
	    my_ymin=(short)get2(fp);
	    my_xmax=(short)get2(fp);
	    my_ymax=(short)get2(fp);

	glyf_ctour_endpts = (unsigned short *)
		calloc(sizeof(unsigned short), glyf_nctours);
	if (glyf_ctour_endpts==NULL) MemExit();

/* if (glyf_nctours > 0) */
	for (i = 0; i < glyf_nctours; i++)
		glyf_ctour_endpts[i] = get2(fp);
	glyf_npts = glyf_ctour_endpts[glyf_nctours-1] + 1;
	j = get2(fp);		/* # of instructions */
	while (j--) getc(fp);	/* ? skip instructions */

	glyf_flag = (unsigned char *) calloc(sizeof(unsigned char), glyf_npts);
	if (glyf_flag==NULL) MemExit();
	glyf_x = (short *) calloc(sizeof(short), glyf_npts);
	if (glyf_x==NULL) MemExit();
	glyf_y = (short *) calloc(sizeof(short), glyf_npts);
	if (glyf_y==NULL) MemExit();

/* flags */
	for (j = 0; j < glyf_npts;) {
		glyf_flag[j++] = c = getc(fp);
		if (c&8) {		/* repeat */
			ct = getc(fp);
			while (ct--) glyf_flag[j++] = c;
		}
	}

/* x coordinates */
	for (j = 0; j < glyf_npts; j++) {
		if (glyf_flag[j] & 2) {
			c = getc(fp);
			glyf_x[j] = (glyf_flag[j] & 0x10)?
				((short) c) : (-1 * (short) c);
		}
		else if (glyf_flag[j] & 0x10) glyf_x[j] = 0;
		else glyf_x[j] = (short) get2(fp);
	}

/* y coordinates */
	for (j = 0; j < glyf_npts; j++) {
		if (glyf_flag[j] & 4) {
			c = getc(fp);
			glyf_y[j] = (glyf_flag[j] & 0x20)?
				((short) c) : (-1 * (short) c);
		}
		else if (glyf_flag[j] & 0x20) glyf_y[j] = 0;
		else glyf_y[j] = (short) get2(fp);
	}

/* x, y coordinate is always relative to previous one */
	for (j = 1; j < glyf_npts; j++) {
		glyf_x[j] += glyf_x[j-1];
		glyf_y[j] += glyf_y[j-1];
	}

	for (j = 0; j < glyf_npts; j++) {
		glyf_x[j] = ((long)(glyf_x[j] - xmin)*scl);
		glyf_y[j] = ((long)(glyf_y[j] - ymin)*scl);
	/* res x res, 1/4 precision, ** must shift coor before scale */
		/*glyf_x[j] = (((long)(glyf_x[j]-xmin))*res/(EM/4))-2;
		glyf_y[j] = (((long)(glyf_y[j]-ymin))*res/(EM/4))-2; */
	}

    /* transform by a matrix */
	if (g_xx != 1.0 || g_yy != 1.0 || g_xy != 0.0 || g_yx != 0.0) {
	    for (j = 0; j < glyf_npts; j++) {
		x = glyf_x[j] * g_xx + glyf_y[j] * g_yx;
		y = glyf_x[j] * g_xy + glyf_y[j] * g_yy;
		glyf_x[j] = (short) x;
		glyf_y[j] = (short) y;
	    }
	}
    /* translate */
	if (g_xoff || g_yoff) {
	    g_xoff *= scl;
	    g_yoff *= scl;
	    for (j = 0; j < glyf_npts; j++) {
		glyf_x[j] += g_xoff;
		glyf_y[j] += g_yoff;
	    }
	}

	return 1;
}

void putBitmap85_(unsigned char *a, int arraylen)
{
 	int j;
 	for (j=0; j<arraylen; ++j)
 		fprintf(out, (!((j+4)%40))? "\n%02x" : "%02x", a[j]);
}

