/* $Id: macbinary.c 4532 2015-12-22 13:18:53Z mskala $ */
/* Copyright (C) 2000-2012  George Williams
 * Copyright (C) 2015  Matthew Skala
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * The name of the author may not be used to endorse or promote products
 * derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "fontanvilvw.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <ustring.h>
#include "ttf.h"
#include "psfont.h"
#include <utype.h>

const int mac_dpi=72;

/* I had always assumed that the mac still believed in 72dpi screens, but I */
/*  see that in geneva under OS/9, the pointsize does not match the pixel */
/*  size of the font. But the dpi is not constant (and the differences */
/*  excede those supplied by rounding errors) varying between 96 and 84dpi */

/* A Mac Resource fork */
/*  http://developer.apple.com/techpubs/mac/MoreToolbox/MoreToolbox-9.html */
/*    begins with a 16 byte header containing: */
/*	resource start offset */
/*	map start offset */
/*	resource length */
/*	map length */
/*    then 256-16 bytes of zeros */
/*    the resource section consists of (many) */
/*	4 byte length count */
/*	resource data	*/
/*    the map section contains */
/*	A copy of the 16 byte header */
/*	a 4 byte mac internal value (I hope) */
/*	another 4 bytes of mac internal values (I hope) */
/*	a 2 byte offset from the start of the map section to the list of resource types */
/*	a 2 byte offset from the start of the map section to the list of resource names */
/*	The resource type list consists of */
/*	    a 2 byte count of the number of resource types (-1) */
/*	    (many copies of) */
/*		a 4 byte resource type ('FOND' for example) */
/*		a 2 byte count of the number of resources of this type (-1) */
/*		a 2 byte offset from the type list start to the resource table */
/*	    a resource table looks like */
/*		a 2 byte offset from the resource name table to a pascal */
/*			string containing this resource's name (or 0xffff for none) */
/*		1 byte of resource flags */
/*		3 bytes of offset from the resource section to the length & */
/*			data of this instance of the resource type */
/*		4 bytes of 0 */
/*	The resource name section consists of */
/*	    a bunch of pascal strings (ie. preceded by a length byte) */

/* The POST resource isn't noticeably documented, it's pretty much a */
/*  straight copy of the pfb file cut up into 0x800 byte chunks. */
/*  (each section of the pfb file has its own set of chunks, the last may be smaller than 0x800) */
/* The NFNT resource http://developer.apple.com/techpubs/mac/Text/Text-250.html */
/* The FOND resource http://developer.apple.com/techpubs/mac/Text/Text-269.html */
/* The sfnt resource is basically a copy of the ttf file */

/* A MacBinary file */
/*  http://www.lazerware.com/formats/macbinary.html */
/*    begins with a 128 byte header */
/*	(which specifies lengths for data/resource forks) */
/*	(and contains mac type/creator data) */
/*	(and other stuff) */
/*	(and finally a crc checksum) */
/*    is followed by the data section (padded to a mult of 128 bytes) */
/*    is followed by the resource section (padded to a mult of 128 bytes) */

/* Crc code taken from: */
/* http://www.ctan.org/tex-archive/tools/macutils/crc/ */
/* MacBinary files use the same CRC that binhex does (in the MacBinary header) */
extern unsigned long binhex_crc(unsigned char *buffer, int size);

/* ******************************** Creation ******************************** */

static uint16_t HashToId(char *fontname,SplineFont *sf,EncMap *map) {
   int low=128, high=0x3fff;

   /* A FOND ID should be between these two numbers for roman script (I think) */
   uint32_t hash=0;
   int i, gid;
   SplineChar *sc;

   /* Figure out what language we've got */
   /*  I'm not bothering with all of the apple scripts, and I don't know */
   /*  what to do about cjk fonts */
   if (sf->cidmaster != NULL || sf->subfontcnt != 0) {
      if (sf->cidmaster != NULL)
	 sf=sf->cidmaster;
      if (sf->ordering != NULL) {
	 if (strstrmatch(sf->ordering, "Japan") != NULL) {
	    low=0x4000;
	    high=0x41ff;
	 } else if (strstrmatch(sf->ordering, "Korea") != NULL) {
	    low=0x4400;
	    high=0x45ff;
	 } else if (strstrmatch(sf->ordering, "CNS") != NULL) {
	    low=0x4200;
	    high=0x43ff;
	 } else if (strstrmatch(sf->ordering, "GB") != NULL) {
	    low=0x7200;
	    high=0x73ff;
	 }
      }
   } else if (map->enc->is_tradchinese) {
      low=0x4200;
      high=0x43ff;
   } else if (map->enc->is_japanese) {
      low=0x4000;
      high=0x41ff;
   } else if (map->enc->is_korean) {
      low=0x4400;
      high=0x45ff;
   } else if (map->enc->is_simplechinese) {
      low=0x7200;
      high=0x73ff;
   } else
      for (i=0; i<map->enccount && i<256; ++i)
	 if ((gid=map->map[i]) != -1 && (sc=sf->glyphs[gid]) != NULL) {
	    /* Japanese between     0x4000 and 0x41ff */
	    /* Trad Chinese         0x4200 and 0x43ff */
	    /*  Simp Chinese        0x7200 and 0x73ff */
	    /* Korean               0x4400 and 0x45ff */
	    if ((sc->unicodeenc >= 0x0600 && sc->unicodeenc<0x0700) ||
		(sc->unicodeenc >= 0xFB50 && sc->unicodeenc<0xfe00)) {
	       /* arabic */
	       low=0x4600;
	       high=0x47ff;
	       break;
	    } else if ((sc->unicodeenc >= 0x0590 && sc->unicodeenc<0x0600)
		       || (sc->unicodeenc >= 0xFB1d
			   && sc->unicodeenc<0xFB50)) {
	       /* hebrew */
	       low=0x4800;
	       high=0x49ff;
	       break;
	    } else if (((sc->unicodeenc >= 0x0370 && sc->unicodeenc<0x0400) || (sc->unicodeenc >= 0x1f00 && sc->unicodeenc<0x2000)) && sc->unicodeenc != 0x3c0) {	/* In mac encoding */
	       /* greek */
	       low=0x4a00;
	       high=0x4bff;
	       break;
	    } else if (sc->unicodeenc >= 0x0400 && sc->unicodeenc<0x0530) {
	       /* cyrillic */
	       low=0x4c00;
	       high=0x4dff;
	       break;
	       /* hebrew/arabic symbols 4e00-4fff */
	    } else if (sc->unicodeenc >= 0x0900 && sc->unicodeenc<0x0980) {
	       /* devanagari */
	       low=0x5000;
	       high=0x51ff;
	       break;
	    } else if (sc->unicodeenc >= 0x0980 && sc->unicodeenc<0x0a00) {
	       /* bengali: script=13 */
	       low=0x5800;
	       high=0x59ff;
	       break;
	    }
	 }
   while (*fontname) {
      int temp=(hash >> 28)&0xf;

      hash=(hash << 4)|temp;
      hash ^= *fontname++-' ';
   }
   hash %= (high-low+1);
   hash += low;
   return (hash);
}

static int IsMacMonospaced(SplineFont *sf,EncMap *map) {
   /* Only look at first 256 */
   int i;
   double width=0x80000000;

   for (i=0; i<256 && i<map->enccount; ++i) {
      int gid=map->map[i];

      if (gid != -1 && SCWorthOutputting(sf->glyphs[gid])) {
	 if (width==0x80000000)
	    width=sf->glyphs[gid]->width;
	 else if (sf->glyphs[gid]->width != width)
	    return (false);
      }
   }
   return (true);
}

static double SFMacWidthMax(SplineFont *sf,EncMap *map) {
   /* Only look at first 256 */
   int i, gid;
   double width=-1;

   for (i=0; i<256 && i<map->enccount; ++i) {
      if ((gid=map->map[i]) != -1 && SCWorthOutputting(sf->glyphs[gid])) {
	 if (sf->glyphs[gid]->width>width)
	    width=sf->glyphs[gid]->width;
      }
   }
   if (width<0)		/* No chars, or widths the mac doesn't support */
      return (0);

   return (width);
}

static int SFMacAnyKerns(SplineFont *sf,EncMap *map) {
   /* Only look at first 256 */
   int i, cnt=0, gid;
   KernPair *kp;

   for (i=0; i<256 && i<map->enccount; ++i) {
      if ((gid=map->map[i]) != -1 && sf->glyphs[gid] != NULL) {
	 for (kp=sf->glyphs[gid]->kerns; kp != NULL; kp=kp->next)
	    if (map->backmap[kp->sc->orig_pos]<256)
	       ++cnt;
      }
   }
   return (cnt);
}

struct resource {
   uint32_t pos;
   uint8_t flags;
   uint16_t id;
   char *name;
   uint32_t nameloc;
   uint32_t nameptloc;
};

struct resourcetype {
   uint32_t tag;
   struct resource *res;
   uint32_t resloc;
};

struct macbinaryheader {
   char *macfilename;
   char *binfilename;		/* if macfilename is null and this is set we will figure out macfilename by removing .bin */
   uint32_t type;
   uint32_t creator;
};

static struct resource *PSToResources(AFILE *res,AFILE *pfbfile) {
   /* split the font up into as many small resources as we need and return */
   /*  an array pointing to the start of each */
   off_t pfbsize;
   int cnt, type;
   struct resource *resstarts;
   int len, i;

   pfbsize=afilesize(pfbfile);
   cnt=3*(pfbsize+0x800)/(0x800-2)+1;
   /* should be (usually) a vast overestimate */
   resstarts=calloc(cnt+1,sizeof(struct resource));

   cnt=0;
   while (1) {
      if (agetc(pfbfile) != 0x80) {
	 ErrorMsg(2,"We made a pfb file, but didn't get one.\n");
	 return (NULL);
      }
      type=agetc(pfbfile);
      if (type==3) {
	 /* 501 appears to be magic */
	 /* postscript resources seem to have flags of 0 */
	 resstarts[cnt].id=501+cnt;
	 resstarts[cnt++].pos=aftell(res);
	 putlong(res, 2);	/* length */
	 aputc(5, res);		/* eof mark */
	 aputc(0, res);
	 break;
      }
      len=agetc(pfbfile);
      len |= (agetc(pfbfile)) << 8;
      len |= (agetc(pfbfile)) << 16;
      len |= (agetc(pfbfile)) << 24;
      while (len>0) {
	 int ilen=len;

	 if (ilen>0x800-2)
	    ilen=0x800-2;
	 len -= ilen;
	 resstarts[cnt].id=501+cnt;
	 resstarts[cnt++].pos=aftell(res);
	 putlong(res, ilen+2);	/* length */
	 aputc(type, res);	/* section type mark */
	 aputc(0, res);
	 for (i=0; i<ilen; ++i)
	    aputc(agetc(pfbfile), res);
      }
   }
   resstarts[cnt].pos=0;
   return (resstarts);
}

static uint32_t TTFToResource(AFILE *res,AFILE *ttffile) {
   /* A truetype font just gets dropped into a resource */
   off_t ttfsize;
   int ch;
   uint32_t resstart;

   ttfsize=afilesize(ttffile);
   resstart=aftell(res);

   putlong(res,ttfsize);
   while ((ch=agetc(ttffile)) != EOF)
      aputc(ch, res);
   return (resstart);
}

static int BDFCCopyBitmaps(uint8_t ** rows,int offset,BDFChar *bdfc,
			   BDFFont * bdf) {
   int i, r, y, ipos, j, c;

   y=bdf->ascent-1;
   r=i=0;
   if (bdfc->ymax>bdf->ascent-1)
      i=bdfc->ymax-(bdf->ascent-1);
   else if (bdfc->ymax<bdf->ascent-1) {
      r=bdf->ascent-1-bdfc->ymax;
      y=bdfc->ymax;
   }
   for (; y >= bdfc->ymin && y >= -bdf->descent; --y, ++i) {
      /* Mac characters may not extend above the ascent or below the descent */
      /*  but bdf chars can, so if a bdf char does, just ignore that part */
      ipos=i * bdfc->bytes_per_line;
      for (j=0, c=offset; j <= bdfc->xmax-bdfc->xmin; ++j, ++c) {
	 if (bdfc->bitmap[ipos+(j >> 3)]&(1 << (7-(j&7))))
	    rows[r][c >> 3] |= (1 << (7-(c&7)));
      }
      ++r;
   }
   return (offset+bdfc->xmax-bdfc->xmin+1);
}

static uint32_t BDFToNFNT(AFILE *res,BDFFont *bdf,EncMap *map) {
   short widths[258], lbearings[258], locs[258] /*, idealwidths[256] */ ;
   uint8_t **rows=malloc(bdf->pixelsize * sizeof(uint8_t *));
   int i, k, width, kernMax=1, descentMax=bdf->descent-1, rectMax =
      1, widMax=3;
   uint32_t rlenpos=aftell(res), end, owloc, owpos;
   int gid;
   BDFChar *bdfc;

   for (i=0; i<map->enccount; i++)
      if ((gid=map->map[i]) != -1 && (bdfc=bdf->glyphs[gid]) != NULL)
	 BCPrepareForOutput(bdfc, true);

   for (i=width=0; i<256 && i<map->enccount; ++i) {
      if ((gid=map->map[i]) != -1 && gid<bdf->glyphcnt
	  && bdf->glyphs[gid] != NULL) {
	 width += bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
	 if (bdf->glyphs[gid]->width>widMax)
	    widMax=bdf->glyphs[gid]->width;
	 if (bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin>rectMax)
	    rectMax=bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
	 if (bdf->glyphs[gid]->xmin<kernMax)
	    kernMax=bdf->glyphs[gid]->xmin;
	 if (bdf->glyphs[gid]->ymin<-descentMax)
	    descentMax=-bdf->glyphs[gid]->ymin;
      }
   }
   if (descentMax>bdf->descent)
      descentMax=bdf->descent;
   ++width;			/* For the "undefined character */
   for (k=0; k<bdf->pixelsize; ++k)
      rows[k]=calloc((width+7)/8+4, sizeof(uint8_t));
   for (i=width=0; i<256; ++i) {
      locs[i]=width;
      if (i >= map->enccount || (gid=map->map[i])==-1
	  || gid >= bdf->glyphcnt || bdf->glyphs[gid]==NULL
	  || !SCWorthOutputting(bdf->glyphs[gid]->sc)) {
	 lbearings[i]=0xff;
	 widths[i]=0xff;
	 /*idealwidths[i]=1<<12; */ /* 1 em */
      } else {
	 lbearings[i]=bdf->glyphs[gid]->xmin-kernMax;
	 widths[i]=bdf->glyphs[gid]->width<0?0 :
	    bdf->glyphs[gid]->width >= 256?255:bdf->glyphs[gid]->width;
	 /*idealwidths[i]=bdf->glyphs[gid]->sc->width*(1<<12)/(bdf->sf->ascent+bdf->sf->descent); */
	 width=BDFCCopyBitmaps(rows, width, bdf->glyphs[gid], bdf);
      }
   }
   /* Now for the "undefined character", just a simple vertical bar */
   locs[i]=width;
   lbearings[i]=1;
   widths[i++]=3;
   /*idealwidths[i++]=(3<<12)/bdf->pixelsize; */
   for (k=1; k<bdf->pixelsize-1; ++k)
      rows[k][width >> 3] |= (1 << (7-(width&7)));
   /* And one more entry to give a size to the last character */
   locs[i]=++width;
   lbearings[i]=widths[i]=0xff;
   /*idealwidths[i]=0; */

   /* Mac magic */
   lbearings[0]=widths[0]=0;
   lbearings['\r']=widths['\r']=0;
   lbearings['\t']=0;
   widths['\t']=6;

   for (i=0; i<map->enccount; i++)
      if ((gid=map->map[i]) != -1 && (bdfc=bdf->glyphs[gid]) != NULL)
	 BCRestoreAfterOutput(bdfc);

   /* We've finished the bitmap conversion, now save it... */
   putlong(res, 0);		/* Length, to be filled in later */
   aput_int16_be_checked(IsMacMonospaced(bdf->sf, map)?0xb000:0x9000,res);	/* fontType */
   aput_int16_be_checked(0,res);
   aput_int16_be_checked(255,res);
   aput_int16_be_checked(widMax,res);
   aput_int16_be_checked(kernMax,res);
   aput_int16_be_checked(-descentMax,res);
   aput_int16_be_checked(rectMax,res);
   aput_int16_be_checked(bdf->pixelsize,res);
   owpos=aftell(res);
   aput_int16_be_checked(0,res);
   aput_int16_be_checked(bdf->ascent,res);
   aput_int16_be_checked(bdf->descent,res);
   aput_int16_be_checked(bdf->sf->pfminfo.linegap * bdf->pixelsize /
		     (bdf->sf->ascent+bdf->sf->descent),res);
   aput_int16_be_checked((width+15) >> 4,res);
   /* bitmaps */
   for (k=0; k<bdf->pixelsize; ++k) {
      for (i=0; i<((width+15) >> 4); ++i) {
	 aputc(rows[k][2*i], res);
	 aputc(rows[k][2*i+1], res);
      }
   }
   for (i=0; i<258; ++i)
      aput_int16_be_checked(locs[i],res);
   owloc=aftell(res);		/* valgrind reports an error here (but not above). god knows why */
   for (i=0; i<258; ++i) {
      aputc(lbearings[i], res);
      aputc(widths[i], res);
   }
   end=aftell(res);
   afseek(res, rlenpos, SEEK_SET);
   putlong(res, end-rlenpos-4);
   afseek(res, owpos, SEEK_SET);
   aput_int16_be_checked((owloc-owpos)/2,res);
   afseek(res, 0, SEEK_END);

   for (k=0; k<bdf->pixelsize; ++k)
      free(rows[k]);
   free(rows);

   return (rlenpos);
}

static uint32_t DummyNFNT(AFILE *res,BDFFont *bdf,EncMap *map) {
   /* This produces a stub NFNT which appears when the real data lives inside */
   /*  an sfnt (truetype) resource. We still need to produce an NFNT to tell */
   /*  the system that the pointsize is available. This NFNT has almost nothing */
   /*  in it, just the initial header, no metrics, no bitmaps */
   int i, width, kernMax=1, descentMax=bdf->descent-1, rectMax =
      1, widMax=3;
   uint32_t rlenpos=aftell(res);
   int gid;

   for (i=width=0; i<256 && i<map->enccount; ++i)
      if ((gid=map->map[i]) != -1 && gid<bdf->glyphcnt
	  && bdf->glyphs[gid] != NULL) {
	 width += bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
	 if (bdf->glyphs[gid]->width>widMax)
	    widMax=bdf->glyphs[gid]->width;
	 if (bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin>rectMax)
	    rectMax=bdf->glyphs[gid]->xmax+1-bdf->glyphs[gid]->xmin;
	 if (bdf->glyphs[gid]->xmin<kernMax)
	    kernMax=bdf->glyphs[gid]->xmin;
	 if (bdf->glyphs[gid]->ymin<-descentMax)
	    descentMax=-bdf->glyphs[gid]->ymin;
      }
   if (descentMax>bdf->descent)
      descentMax=bdf->descent;

   putlong(res, 26);		/* Length */
   aput_int16_be_checked(SFOneWidth(bdf->sf) != -1?0xf000:0xd000,res);	/* fontType */
   aput_int16_be_checked(0,res);
   aput_int16_be_checked(255,res);
   aput_int16_be_checked(widMax,res);
   aput_int16_be_checked(kernMax,res);
   aput_int16_be_checked(-descentMax,res);
   aput_int16_be_checked(rectMax,res);
   aput_int16_be_checked(bdf->pixelsize,res);
   aput_int16_be_checked(0,res);
   aput_int16_be_checked(bdf->ascent,res);
   aput_int16_be_checked(bdf->descent,res);
   aput_int16_be_checked((bdf->sf->pfminfo.linegap * bdf->pixelsize /
		     (bdf->sf->ascent+bdf->sf->descent)),res);
   aput_int16_be_checked(0,res);

   return (rlenpos);
}

static struct resource *SFToNFNTs(AFILE *res,SplineFont *sf,int32_t *sizes,
				  EncMap * map) {
   int i, baseresid=HashToId(sf->fontname, sf, map);
   struct resource *resstarts;
   BDFFont *bdf;

   if (sf->cidmaster != NULL)
      sf=sf->cidmaster;

   for (i=0; sizes[i] != 0; ++i);
   resstarts=calloc(i+1, sizeof(struct resource));

   for (i=0; sizes[i] != 0; ++i) {
      if ((sizes[i] >> 16) != 1)
	 continue;
      if ((sizes[i]&0xffff) >= 256)
	 continue;
      for (bdf=sf->bitmaps;
	   bdf != NULL && (bdf->pixelsize != (sizes[i]&0xffff)
			   || BDFDepth(bdf) != 1); bdf=bdf->next);
      if (bdf==NULL)
	 continue;
      resstarts[i].id=baseresid+bdf->pixelsize;
      resstarts[i].pos=BDFToNFNT(res, bdf, map);
      /* NFNTs seem to have resource flags of 0 */
   }
   return (resstarts);
}

static struct resource *SFsToNFNTs(AFILE *res,struct sflist *sfs,
				   int baseresid) {
   int i, j, cnt;
   struct resource *resstarts;
   BDFFont *bdf;
   struct sflist *sfi;
   SplineFont *sf;

   cnt=0;
   for (sfi=sfs; sfi != NULL; sfi=sfi->next) {
      if (sfi->sizes != NULL) {
	 for (i=0; sfi->sizes[i] != 0; ++i);
	 cnt += i;
	 sfi->ids=calloc(i+1, sizeof(int));
	 sfi->bdfs=calloc(i+1, sizeof(BDFFont *));
      }
   }

   resstarts=calloc(cnt+1, sizeof(struct resource));

   cnt=0;
   for (sfi=sfs; sfi != NULL; sfi=sfi->next) {
      sf=sfi->sf;
      if (sf->cidmaster != NULL)
	 sf=sf->cidmaster;
      j=0;
      if (sfi->sizes)
	 for (i=0; sfi->sizes[i] != 0; ++i) {
	    if ((sfi->sizes[i] >> 16) != 1)
	       continue;
	    if ((sfi->sizes[i]&0xffff) >= 256)
	       continue;
	    for (bdf=sf->bitmaps;
		 bdf != NULL && (bdf->pixelsize != (sfi->sizes[i]&0xffff)
				 || BDFDepth(bdf) != 1); bdf=bdf->next);
	    if (bdf==NULL)
	       continue;
	    sfi->ids[j]=baseresid;
	    sfi->bdfs[j]=bdf;
	    resstarts[cnt+j].id=baseresid++;
	    resstarts[cnt+j++].pos=BDFToNFNT(res, bdf, sfi->map);
	    /* NFNTs seem to have resource flags of 0 */
	 }
      cnt += j;
   }
   return (resstarts);
}

static struct resource *BuildDummyNFNTlist(AFILE *res,SplineFont *sf,
					   int32_t * sizes, int baseresid,
					   EncMap * map) {
   int i;
   struct resource *resstarts;
   BDFFont *bdf;

   if (sf->cidmaster != NULL)
      sf=sf->cidmaster;

   for (i=0; sizes[i] != 0; ++i);
   resstarts=calloc(i+1, sizeof(struct resource));

   for (i=0; sizes[i] != 0; ++i) {
      if ((sizes[i] >> 16) != 1)
	 continue;
      if ((sizes[i]&0xffff) >= 256)
	 continue;
      for (bdf=sf->bitmaps;
	   bdf != NULL && (bdf->pixelsize != (sizes[i]&0xffff)
			   || BDFDepth(bdf) != 1); bdf=bdf->next);
      if (bdf==NULL)
	 continue;
      resstarts[i].id=baseresid+(sizes[i]&0xffff);
      resstarts[i].pos=DummyNFNT(res, bdf, map);
      /* NFNTs seem to have resource flags of 0 */
   }
   return (resstarts);
}

static struct resource *BuildDummyNFNTfamilyList(AFILE *res,
						 struct sflist *sfs,
						 int baseresid) {
   int i, j, cnt;
   struct resource *resstarts;
   BDFFont *bdf;
   struct sflist *sfi;
   SplineFont *sf;

   cnt=0;
   for (sfi=sfs; sfi != NULL; sfi=sfi->next) {
      if (sfi->sizes != NULL) {
	 for (i=0; sfi->sizes[i] != 0; ++i);
	 cnt += i;
	 sfi->ids=calloc(i+1, sizeof(int));
	 sfi->bdfs=calloc(i+1, sizeof(BDFFont *));
      }
   }

   resstarts=calloc(cnt+1, sizeof(struct resource));

   cnt=0;
   for (sfi=sfs; sfi != NULL; sfi=sfi->next) {
      sf=sfi->sf;
      j=0;
      if (sf->cidmaster != NULL)
	 sf=sf->cidmaster;
      if (sfi->sizes)
	 for (i=0; sfi->sizes[i] != 0; ++i) {
	    if ((sfi->sizes[i] >> 16) != 1)
	       continue;
	    for (bdf=sf->bitmaps;
		 bdf != NULL && (bdf->pixelsize != (sfi->sizes[i]&0xffff)
				 || BDFDepth(bdf) != 1); bdf=bdf->next);
	    if (bdf==NULL)
	       continue;
	    sfi->ids[j]=baseresid;
	    sfi->bdfs[j]=bdf;
	    resstarts[cnt+j].id=baseresid++;
	    resstarts[cnt+j++].pos=DummyNFNT(res, bdf, sfi->map);
	    /* NFNTs seem to have resource flags of 0 */
	 }
      cnt += j;
   }
   return (resstarts);
}

enum psstyle_flags { psf_bold=1, psf_italic=2, psf_outline=4,
   psf_shadow=0x8, psf_condense=0x10, psf_extend=0x20
};

uint16_t _MacStyleCode(char *styles, SplineFont *sf, uint16_t * psstylecode) {
   unsigned short stylecode=0, psstyle=0;

   if (strstrmatch(styles, "Bold") || strstrmatch(styles, "Demi") ||
       strstrmatch(styles, "Heav") || strstrmatch(styles, "Blac") ||
/* A few fonts have German/French styles in their names */
       strstrmatch(styles, "Fett") || strstrmatch(styles, "Gras")) {
      stylecode=sf_bold;
      psstyle=psf_bold;
   } else if (sf != NULL && sf->weight != NULL &&
	      (strstrmatch(sf->weight, "Bold")
	       || strstrmatch(sf->weight, "Demi")
	       || strstrmatch(sf->weight, "Heav")
	       || strstrmatch(sf->weight, "Blac")
	       || strstrmatch(sf->weight, "Fett")
	       || strstrmatch(sf->weight, "Gras"))) {
      stylecode=sf_bold;
      psstyle=psf_bold;
   }
   /* URW uses four leter abbreviations of Italic and Oblique */
   /* Somebody else uses two letter abbrevs */
   if ((sf != NULL && sf->italicangle != 0) ||
       strstrmatch(styles, "Ital") ||
       strstrmatch(styles, "Obli") ||
       strstrmatch(styles, "Slanted") ||
       strstrmatch(styles, "Kurs") || strstr(styles, "It")) {
      stylecode |= sf_italic;
      psstyle |= psf_italic;
   }
   if (strstrmatch(styles, "Underline")) {
      stylecode |= sf_underline;
   }
   if (strstrmatch(styles, "Outl")) {
      stylecode |= sf_outline;
      psstyle |= psf_outline;
   }
   if (strstr(styles, "Shadow") != NULL) {
      stylecode |= sf_shadow;
      psstyle |= psf_shadow;
   }
   if (strstrmatch(styles, "Cond") || strstr(styles, "Cn") ||
       strstrmatch(styles, "Narrow")) {
      stylecode |= sf_condense;
      psstyle |= psf_condense;
   }
   if (strstrmatch(styles, "Exte") || strstr(styles, "Ex")) {
      stylecode |= sf_extend;
      psstyle |= psf_extend;
   }
   if ((psstyle&psf_extend) && (psstyle&psf_condense)) {
      if (sf != NULL)
	 ErrorMsg(2,"Warning: %s(%s) is both extended and condensed. That's impossible.\n",
		  sf->fontname, sf->origname);
      else
	 ErrorMsg(2,"Warning: Both extended and condensed. That's impossible.\n");
      psstyle &= ~psf_extend;
      stylecode &= ~sf_extend;
   }
   if (psstylecode != NULL)
      *psstylecode=psstyle;
   return (stylecode);
}

uint16_t MacStyleCode(SplineFont *sf, uint16_t * psstylecode) {
   char *styles;

   if (sf->cidmaster != NULL)
      sf=sf->cidmaster;

   if (sf->macstyle != -1) {
      if (psstylecode != NULL)
	 *psstylecode=(sf->macstyle&0x3)|((sf->macstyle&0x6c) >> 1);
      return (sf->macstyle);
   }

   styles=SFGetModifiers(sf);
   return (_MacStyleCode(styles, sf, psstylecode));
}

static uint32_t SFToFOND(AFILE *res,SplineFont *sf,uint32_t id,int dottf,
		       int32_t * sizes, EncMap * map) {
   uint32_t rlenpos=aftell(res), widoffpos, widoffloc, kernloc, styleloc, end;
   int i, j, k, cnt, strcnt, fontclass, stylecode, glyphenc, geoffset,
      realstylecode;
   int gid;
   KernPair *kp;
   DBounds b;
   char *pt;

   /* Fonds are generally marked system heap and sometimes purgeable (resource flags) */

   putlong(res, 0);		/* Fill in length later */
   aput_int16_be_checked(IsMacMonospaced(sf, map)?0x9000:0x1000,res);
   aput_int16_be_checked(id,res);
   aput_int16_be_checked(0,res);		/* First character */
   aput_int16_be_checked(255,res);		/* Last character */
   aput_int16_be_checked(((sf->ascent * (1 << 12))/(sf->ascent+sf->descent)),res);
   aput_int16_be_checked(-((sf->descent * (1 << 12)) /
		      (sf->ascent+sf->descent)),res);
   aput_int16_be_checked(((sf->pfminfo.linegap * (1 << 12)) /
		     (sf->ascent+sf->descent)),res);
   aput_int16_be_checked(((SFMacWidthMax(sf, map)*(1 << 12)) /
		     (sf->ascent+sf->descent)),res);
   widoffpos=aftell(res);
   putlong(res, 0);		/* Fill in width offset later */
   putlong(res, 0);		/* Fill in kern offset later */
   putlong(res, 0);		/* Fill in style offset later */
   for (i=0; i<9; ++i)
      aput_int16_be_checked(0,res);		/* Extra width values */
   putlong(res, 0);		/* Script for international */
   aput_int16_be_checked(2,res);		/* FOND version */

   /* Font association table */
   stylecode=realstylecode=MacStyleCode(sf, NULL);
   stylecode=0;		/* Debug !!!! */
   for (i=j=0; sizes != NULL && sizes[i] != 0; ++i)
      if ((sizes[i] >> 16)==1 && (sizes[i]&0xffff)<256)
	 ++j;
   if (dottf) {
      aput_int16_be_checked(j+1-1,res);	/* Number of faces */
      aput_int16_be_checked(0,res);		/* it's scaleable */
      aput_int16_be_checked(stylecode,res);
      aput_int16_be_checked(id,res);	/* Give it the same ID as the fond */
   } else
      aput_int16_be_checked(j-1,res);	/* Number of faces */
   if (sizes != NULL) {
      for (i=0; sizes[i] != 0; ++i)
	 if ((sizes[i] >> 16)==1) {
	    aput_int16_be_checked(sizes[i]&0xffff,res);
	    aput_int16_be_checked(stylecode,res);
	    aput_int16_be_checked(id+(sizes[i]&0xffff),res);	/* make up a unique ID */
	 }
   }

   /* offset table */
   aput_int16_be_checked(1-1,res);	/* One table */
   putlong(res, 6);		/* Offset from start of otab to next byte */

   /* bounding box table */
   aput_int16_be_checked(1-1,res);	/* One bounding box */
   SplineFontFindBounds(sf, &b);
   aput_int16_be_checked(stylecode,res);
   aput_int16_be_checked(b.minx * (1 << 12)/(sf->ascent+sf->descent),res);
   aput_int16_be_checked(b.miny * (1 << 12)/(sf->ascent+sf->descent),res);
   aput_int16_be_checked(b.maxx * (1 << 12)/(sf->ascent+sf->descent),res);
   aput_int16_be_checked(b.maxy * (1 << 12)/(sf->ascent+sf->descent),res);

   widoffloc=aftell(res);
   aput_int16_be_checked(1-1,res);	/* One style in the width table too */
   aput_int16_be_checked(stylecode,res);
   for (k=0; k <= 256; ++k) {
      if (k >= map->enccount || k==256 || (gid=map->map[k])==-1
	  || sf->glyphs[gid]==NULL)
	 aput_int16_be_checked(1 << 12,res);	/* 1 em is default size */
      else
	 aput_int16_be_checked(sf->glyphs[gid]->width * (1 << 12)/(sf->ascent +
							sf->descent),res);
   }

   kernloc=0;
   if ((cnt=SFMacAnyKerns(sf, map))>0) {
      kernloc=aftell(res);
      aput_int16_be_checked(1-1,res);	/* One style in the width table too */
      aput_int16_be_checked(stylecode,res);	/* style */
      aput_int16_be_checked(cnt,res);	/* Count of kerning pairs */
      for (k=0; k<256 && k<map->enccount; ++k) {
	 if ((gid=map->map[k]) != -1 && sf->glyphs[gid] != NULL) {
	    for (kp=sf->glyphs[gid]->kerns; kp != NULL; kp=kp->next)
	       if (map->backmap[kp->sc->orig_pos]<256) {
		  aputc(k, res);
		  aputc(map->backmap[kp->sc->orig_pos], res);
                  aput_int16_be_checked(kp->off * (1 << 12)/(sf->ascent+sf->descent),res);
	       }
	 }
      }
   }

   /* Fontographer referenced a postscript font even in truetype FONDs */
   styleloc=aftell(res);
   fontclass=0x1;		/* font name needs coordinating? Font has its own encoding */
   if (!(realstylecode&sf_outline))
      fontclass |= 4;
   if (realstylecode&sf_bold)
      fontclass |= 0x18;
   if (realstylecode&psf_italic)
      fontclass |= 0x40;
   if (realstylecode&psf_condense)
      fontclass |= 0x80;
   if (realstylecode&psf_extend)
      fontclass |= 0x100;
   aput_int16_be_checked(fontclass,res);	/* fontClass */
   geoffset=aftell(res);
   putlong(res, 0);		/* Offset to glyph encoding table */ /* Fill in later */
   putlong(res, 0);		/* Reserved, MBZ */
   if (!sf->familyname
       || strnmatch(sf->familyname, sf->fontname,
		    strlen(sf->familyname)) != 0)
      strcnt=1;
   else if (strmatch(sf->familyname, sf->fontname)==0)
      strcnt=1;
   else if (sf->fontname[strlen(sf->familyname)]=='-')
      strcnt=4;
   else
      strcnt=3;
   for (k=0; k<48; ++k)
      aputc(strcnt==1?1:2, res);	/* All indices point to this font */
   aput_int16_be_checked(strcnt,res);	/* strcnt strings */
   if (strcnt==1) {
      aputc(strlen(sf->fontname), res);	/* basename is full name */
      /* Mac expects this to be upper case */
      if (islower(*sf->fontname))
	 aputc(toupper(*sf->fontname), res);
      else
	 aputc(*sf->fontname, res);
      afwrite(sf->fontname+1, 1, strlen(sf->fontname+1), res);
   } else {
      pt=sf->fontname+strlen(sf->familyname);
      aputc(strlen(sf->familyname), res);	/* basename */
      if (islower(*sf->familyname))
	 aputc(toupper(*sf->familyname), res);
      else
	 aputc(*sf->familyname, res);
      afwrite(sf->familyname+1, 1, strlen(sf->familyname+1), res);
      if (strcnt==3) {
	 aputc(1, res);		/* index string is one byte long */
	 aputc(3, res);		/* plain name is basename with string 2 */
	 aputc(strlen(pt), res);	/* length of... */
	 afwrite(pt, 1, strlen(pt), res);	/* everything else */
      } else {
	 aputc(2, res);		/* index string is two bytes long */
	 aputc(3, res);		/* plain name is basename with hyphen */
	 aputc(4, res);		/* and everything else */
	 aputc(1, res);		/* Length of ... */
	 aputc('-', res);	/* String containing hyphen */
	 ++pt;			/* skip over hyphen */
	 aputc(strlen(pt), res);	/* length of ... */
	 afwrite(pt, 1, strlen(pt), res);	/* everything else */
      }
   }
   /* Greg: record offset for glyph encoding table */
   /* We assume that the bitmap and postscript fonts are encoded similarly */
   /*  and so a null vector will do. */
   /* GWW: Hmm. ATM refuses to use postscript fonts that have */
   /*  glyph encoding tables. Printer drivers use them ok. ATM will only */
   /*  work on fonts with mac roman encodings */
   if (strmatch(map->enc->enc_name, "mac") != 0 &&
       strmatch(map->enc->enc_name, "macintosh") != 0 &&
       strmatch(map->enc->enc_name, "macroman") != 0) {
      if (!dottf)
	 ErrorMsg(1,"ATM requires that fonts be encoded with the Macintosh "
	            "Latin encoding.  This postscript font will print fine, "
	            "but only the bitmap versions will be displayed on the "
	            "screen.\n");
      glyphenc=aftell(res);
      afseek(res, geoffset, SEEK_SET);
      putlong(res, glyphenc-geoffset+2);
      afseek(res, glyphenc, SEEK_SET);
      aput_int16_be_checked(0,res);
   }

   end=aftell(res);
   afseek(res, widoffpos, SEEK_SET);
   putlong(res, widoffloc-rlenpos-4);	/* Fill in width offset */
   putlong(res, kernloc != 0?kernloc-rlenpos-4:0);	/* Fill in kern offset */
   putlong(res, styleloc != 0?styleloc-rlenpos-4:0);	/* Fill in style offset */

   afseek(res, rlenpos, SEEK_SET);
   putlong(res, end-rlenpos-4);	/* resource length */
   afseek(res, end, SEEK_SET);
   return (rlenpos);
}

static void putpnsstring(AFILE *res,char *fontname,int len) {
   aputc(len, res);
   if (*fontname && len>0) {
      if (islower(*fontname))
	 aputc(toupper(*fontname), res);
      else
	 aputc(*fontname, res);
      --len;
      for (++fontname; *fontname && len>0; ++fontname, --len)
	 aputc(*fontname, res);
   }
}

static void putpsstring(AFILE *res,char *fontname) {
   aputc(strlen(fontname), res);
   if (*fontname) {
      for (; *fontname; ++fontname)
	 aputc(*fontname, res);
   }
}

struct sflistlist {
   struct sflist *sfs;
   struct sflistlist *next;
   char *fondname;
};

static struct sflistlist *FondSplitter(struct sflist *sfs,int *fondcnt) {
   struct sflist *psfaces[48], *sfi, *last, *start;
   struct sflistlist *sfsl=NULL, *lastl=NULL, *cur, *test;
   uint16_t psstyle;
   int fc=0;

   sfi=sfs;
   if (sfi->sf->fondname==NULL) {
      memset(psfaces, 0, sizeof(psfaces));
      MacStyleCode(sfi->sf, &psstyle);
      last=NULL;
      while (sfi->sf->fondname==NULL && psfaces[psstyle]==NULL) {
	 psfaces[psstyle]=sfi;
	 last=sfi;
	 sfi=sfi->next;
	 if (sfi==NULL)
	    break;
	 MacStyleCode(sfi->sf, &psstyle);
      }
      cur=calloc(1, sizeof(struct sflistlist));
      cur->sfs=sfs;
      last->next=NULL;
      for (last=sfi; last != NULL; last=last->next)
	 if (last->sf->fondname != NULL
	     && strcmp(last->sf->fondname, sfs->sf->familyname)==0)
	    break;
      cur->fondname =
	 fastrdup(last==NULL?sfs->sf->familyname:sfs->sf->fontname);
      lastl=sfsl=cur;
      ++fc;
   }
   while (sfi != NULL) {
      start=sfi;
      if (sfi->sf->fondname==NULL) {
	 last=sfi;
	 sfi=sfi->next;
      } else {
	 memset(psfaces, 0, sizeof(psfaces));
	 MacStyleCode(sfi->sf, &psstyle);
	 while (sfi != NULL && sfi->sf->fondname != NULL &&
		strcmp(sfi->sf->fondname, start->sf->fondname)==0 &&
		psfaces[psstyle]==NULL) {
	    psfaces[psstyle]=sfi;
	    last=sfi;
	    sfi=sfi->next;
	    if (sfi==NULL)
	       break;
	    MacStyleCode(sfi->sf, &psstyle);
	 }
      }
      cur=calloc(1, sizeof(struct sflistlist));
      test=NULL;
      if (start->sf->fondname != NULL) {
	 for (test=sfsl; test != NULL; test=test->next)
	    if (strcmp(test->fondname, start->sf->fondname)==0)
	       break;
	 if (test==NULL)
	    cur->fondname=fastrdup(start->sf->fondname);
      }
      if (cur->fondname==NULL)
	 cur->fondname=fastrdup(start->sf->fontname);
      if (lastl != NULL)
	 lastl->next=cur;
      lastl=cur;
      cur->sfs=start;
      last->next=NULL;
      if (sfsl==NULL)
	 sfsl=cur;
      ++fc;
   }
   *fondcnt=fc;
   return (sfsl);
}

static void SFListListFree(struct sflistlist *sfsl) {
   struct sflist *last=NULL;
   struct sflistlist *sfli, *sflnext;

   /* free the fond list and restore the sfs list */

   for (sfli=sfsl; sfli != NULL; sfli=sflnext) {
      sflnext=sfli->next;
      if (last != NULL)
	 last->next=sfli->sfs;
      for (last=sfli->sfs; last->next != NULL; last=last->next);
      free(sfli->fondname);
      free(sfli);
   }
}

static uint32_t SFsToFOND(AFILE *res,struct sflist *sfs,uint32_t id,int format,
			int bf) {
   uint32_t rlenpos=aftell(res), widoffpos, widoffloc, kernloc, styleloc, end;
   int i, j, k, cnt, scnt, kcnt, pscnt, strcnt, fontclass, glyphenc, geoffset;
   int gid;
   int size;
   uint16_t psstyle, stylecode;
   int exact, famlen, has_hyphen;
   char *familyname;
   KernPair *kp;
   DBounds b;

   /* Fonds are generally marked system heap and sometimes purgeable (resource flags) */
   struct sflist *faces[96];
   struct sflist *psfaces[48];
   SplineFont *sf;
   struct sflist *sfi;
   char *pt;

   memset(faces, 0, sizeof(faces));
   memset(psfaces, 0, sizeof(psfaces));
   for (sfi=sfs; sfi != NULL; sfi=sfi->next) {
      stylecode=MacStyleCode(sfi->sf, &psstyle);
      if (sfs->next==NULL)	/* FONDs with a single entry should make that entry be "regular" no matter what we think it really is */
	 stylecode=psstyle=0;
      if (faces[stylecode]==NULL)
	 faces[stylecode]=sfi;
      if (psfaces[psstyle]==NULL)
	 psfaces[psstyle]=sfi;
   }
   sf=faces[0]->sf;

   putlong(res, 0);		/* Fill in length later */
   aput_int16_be_checked(IsMacMonospaced(sf, faces[0]->map)?0x9000:0x1000,res);
   aput_int16_be_checked(id,res);
   aput_int16_be_checked(0,res);		/* First character */
   aput_int16_be_checked(255,res);		/* Last character */
   aput_int16_be_checked(
	    ((sf->ascent * (1 << 12))/(sf->ascent+sf->descent)),res);
   aput_int16_be_checked(
	    -((sf->descent * (1 << 12)) /
		      (sf->ascent+sf->descent)),res);
   aput_int16_be_checked(
	    ((sf->pfminfo.linegap * (1 << 12)) /
		     (sf->ascent+sf->descent)),res);
   aput_int16_be_checked(
	    ((SFMacWidthMax(sf, faces[0]->map)*(1 << 12)) /
		     (sf->ascent+sf->descent)),res);
   widoffpos=aftell(res);
   putlong(res, 0);		/* Fill in width offset later */
   putlong(res, 0);		/* Fill in kern offset later */
   putlong(res, 0);		/* Fill in style offset later */
   for (i=0; i<9; ++i)
      aput_int16_be_checked(0,res);		/* Extra width values */
   putlong(res, 0);		/* Script for international */
   aput_int16_be_checked(2,res);		/* FOND version */

   /* Font association table */
   for (i=cnt=scnt=kcnt=0; i<96; ++i)
      if (faces[i] != NULL) {
	 ++scnt;
	 if (faces[i]->id != 0)
	    ++cnt;
	 if (faces[i]->ids != NULL)
	    for (j=0; faces[i]->ids[j] != 0; ++j)
	       ++cnt;
	 if (SFMacAnyKerns(faces[i]->sf, faces[i]->map)>0)
	    ++kcnt;
      }
   aput_int16_be_checked(cnt-1,res);	/* Number of faces */
   /* do ttf faces (if any) first */
   for (i=cnt=0; i<96; ++i)
      if (faces[i] != NULL && faces[i]->id != 0) {
	 aput_int16_be_checked(0,res);	/* it's scaleable */
	 aput_int16_be_checked(i,res);	/* style */
	 aput_int16_be_checked(faces[i]->id,res);
      }
   /* then do bitmap faces (if any) */ /* Ordered by size damn it */
   for (size=1; size<256; ++size) {
      for (i=0; i<96; ++i)
	 if (faces[i] != NULL && faces[i]->ids != NULL) {
	    for (j=0; faces[i]->ids[j] != 0; ++j) {
	       int pointsize =
		  rint((faces[i]->bdfs[j]->pixelsize*72.0/mac_dpi));
	       if (pointsize==size) {
		  aput_int16_be_checked(size,res);
		  aput_int16_be_checked(i,res);	/* style */
		  aput_int16_be_checked(faces[i]->ids[j],res);
	       }
	    }
	 }
   }

   /* offset table */
   aput_int16_be_checked(1-1,res);	/* One table */
   putlong(res, 6);		/* Offset from start of otab to next byte */

   /* bounding box table */
   aput_int16_be_checked(scnt-1,res);	/* One bounding box per style */
   for (i=0; i<96; ++i)
      if (faces[i] != NULL) {
	 SplineFontFindBounds(faces[i]->sf, &b);
	 aput_int16_be_checked(i,res);	/* style */
	 aput_int16_be_checked(
		  b.minx * (1 << 12)/(faces[i]->sf->ascent +
					faces[i]->sf->descent),res);
	 aput_int16_be_checked(
		  b.miny * (1 << 12)/(faces[i]->sf->ascent +
					faces[i]->sf->descent),res);
	 aput_int16_be_checked(
		  b.maxx * (1 << 12)/(faces[i]->sf->ascent +
					faces[i]->sf->descent),res);
	 aput_int16_be_checked(
		  b.maxy * (1 << 12)/(faces[i]->sf->ascent +
					faces[i]->sf->descent),res);
      }

   widoffloc=aftell(res);
   aput_int16_be_checked(scnt-1,res);	/* One set of width metrics per style */
   for (i=0; i<96; ++i)
      if (faces[i] != NULL) {
	 aput_int16_be_checked(i,res);
	 for (k=0; k <= 257; ++k) {
	    if (k >= faces[i]->map->enccount || k >= 256 ||
		(gid=faces[i]->map->map[k])==-1
		|| faces[i]->sf->glyphs[gid]==NULL)
	       aput_int16_be_checked(1 << 12,res);	/* 1 em is default size */
	    else
	       aput_int16_be_checked(
			faces[i]->sf->glyphs[gid]->width * (1 << 12) /
			(faces[i]->sf->ascent+faces[i]->sf->descent),res);
	 }
      }

   kernloc=0;
   if (kcnt>0) {
      kernloc=aftell(res);
      aput_int16_be_checked(kcnt-1,res);	/* Number of styles with kern pairs */
      for (i=0; i<96; ++i)
	 if (faces[i] != NULL
	     && (cnt=SFMacAnyKerns(faces[i]->sf, faces[i]->map))>0) {
	    aput_int16_be_checked(i,res);	/* style */
	    aput_int16_be_checked(cnt,res);	/* Count of kerning pairs */
	    for (k=0; k<256 && k<faces[i]->map->enccount; ++k) {
	       if ((gid=faces[i]->map->map[k]) != -1
		   && faces[i]->sf->glyphs[gid] != NULL) {
		  for (kp=faces[i]->sf->glyphs[gid]->kerns; kp != NULL;
		       kp=kp->next)
		     if (faces[i]->map->backmap[kp->sc->orig_pos]<256) {
			aputc(k, res);
			aputc(faces[i]->map->backmap[kp->sc->orig_pos], res);
			aput_int16_be_checked(
				 kp->off * (1 << 12)/(sf->ascent +
							sf->descent),res);
		     }
	       }
	    }
	 }
   }

   /* Fontographer referenced a postscript font even in truetype FONDs */
   styleloc=aftell(res);

   exact=false;
   familyname=psfaces[0]->sf->fontname;
   famlen=strlen(familyname);
   if ((pt=strchr(familyname, '-')) != NULL)
      famlen=pt-familyname;
   else if (strnmatch(psfaces[0]->sf->familyname, psfaces[0]->sf->fontname,
		      strlen(psfaces[0]->sf->familyname))==0)
      famlen=strlen(psfaces[0]->sf->familyname);
   has_hyphen=(familyname[famlen]=='-');
   for (i=pscnt=0; i<48; ++i)
      if (psfaces[i] != NULL) {
	 ++pscnt;
	 if (strncmp(psfaces[i]->sf->fontname, familyname, famlen) != 0) {
	    while (famlen>0) {
	       --famlen;
	       if (strncmp(psfaces[i]->sf->fontname, familyname, famlen)==0)
		  break;
	    }
	 }
      }
   if (famlen != 0)
      for (i=0; i<48; ++i)
	 if (psfaces[i] != NULL) {
	    if (psfaces[i]->sf->fontname[famlen]==0)
	       exact=true;
	 }
   fontclass=0x1;
   if (psfaces[psf_outline]==NULL)
      fontclass |= 4;
   if (psfaces[psf_bold] != NULL)
      fontclass |= 0x18;
   if (psfaces[psf_italic] != NULL)
      fontclass |= 0x40;
   if (psfaces[psf_condense] != NULL)
      fontclass |= 0x80;
   if (psfaces[psf_extend] != NULL)
      fontclass |= 0x100;
   aput_int16_be_checked(fontclass,res);	/* fontClass */
   geoffset=aftell(res);
   putlong(res, 0);		/* Offset to glyph encoding table */ /* Fill in later */
   putlong(res, 0);		/* Reserved, MBZ */
   strcnt =
      1 /* Family Name */ +pscnt-exact /* count of format strings */  +
      has_hyphen+pscnt-exact /* count of additional strings */ ;
   /* indices to format strings */
   for (i=0, pscnt=2; i<48; ++i)
      if (psfaces[i] != NULL && psfaces[i]->sf->fontname[famlen] != 0)
	 aputc(pscnt++, res);
      else if (exact)
	 aputc(1, res);
      else
	 aputc(2, res);
   aput_int16_be_checked(strcnt,res);	/* strcnt strings */
   putpnsstring(res, familyname, famlen);
   if (has_hyphen)
      has_hyphen=pscnt++;	/* Space for hyphen if present */
   /* Now the format strings */
   for (i=0; i<48; ++i)
      if (psfaces[i] != NULL) {
	 if (psfaces[i]->sf->fontname[famlen] != 0) {
	    if (has_hyphen && psfaces[i]->sf->fontname[famlen]==' ') {
	       aputc(2, res);
	       aputc(has_hyphen, res);
	       aputc(pscnt++, res);
	    } else {
	       aputc(1, res);	/* Familyname with the following */
	       aputc(pscnt++, res);
	    }
	 }
      }
   if (has_hyphen) {
      aputc(1, res);
      aputc('-', res);
   }
   /* Now the additional names */
   for (i=0; i<48; ++i)
      if (psfaces[i] != NULL) {
	 if (psfaces[i]->sf->fontname[famlen] != 0)
	    putpsstring(res, psfaces[i]->sf->fontname+famlen);
      }
   /* Greg: record offset for glyph encoding table */
   /* We assume that the bitmap and postscript fonts are encoded similarly */
   /*  and so a null vector will do. */
   /* GWW: Hmm. ATM refuses to use postscript fonts that have */
   /*  glyph encoding tables. Printer drivers use them ok. ATM will only */
   /*  work on fonts with mac roman encodings */
   if (strmatch(psfaces[0]->map->enc->enc_name, "mac") != 0 &&
       strmatch(psfaces[0]->map->enc->enc_name, "macintosh") != 0 &&
       strmatch(psfaces[0]->map->enc->enc_name, "macroman") != 0) {
      if (format==ff_pfbmacbin)
	 ErrorMsg(1,"ATM requires that fonts be encoded with the Macintosh "
	            "Latin encoding.  This postscript font will print fine, "
	            "but only the bitmap versions will be displayed on the "
	            "screen.\n");
      glyphenc=aftell(res);
      afseek(res, geoffset, SEEK_SET);
      putlong(res, glyphenc-geoffset+2);
      afseek(res, glyphenc, SEEK_SET);
      aput_int16_be_checked(0,res);		/* Greg: an empty Glyph encoding table */
   }

   end=aftell(res);
   afseek(res, widoffpos, SEEK_SET);
   putlong(res, widoffloc-rlenpos-4);	/* Fill in width offset */
   putlong(res, kernloc != 0?kernloc-rlenpos-4:0);	/* Fill in kern offset */
   putlong(res, styleloc != 0?styleloc-rlenpos-4:0);	/* Fill in style offset */

   afseek(res, rlenpos, SEEK_SET);
   putlong(res, end-rlenpos-4);	/* resource length */
   afseek(res, end, SEEK_SET);
   return (rlenpos);
}

/* I presume this routine is called after all resources have been written */
static void DumpResourceMap(AFILE *res,struct resourcetype *rtypes,
			    enum fontformat format) {
   uint32_t rfork_base=format >= ff_ttfdfont?0:128;	/* space for mac binary header */
   uint32_t resource_base=rfork_base+0x100;
   uint32_t rend, rtypesstart, mend, namestart;
   int i, j;

   afseek(res, 0, SEEK_END);
   rend=aftell(res);

   if (format<ff_ttfdfont) {
      /* Duplicate resource header */
      putlong(res, 0x100);	/* start of resource data */
      putlong(res, rend-rfork_base);	/* start of resource map */
      putlong(res, rend-rfork_base-0x100);	/* length of resource data */
      putlong(res, 0);		/* don't know the length of the map section yet */
   } else {
      for (i=0; i<16; ++i)	/* 16 bytes of zeroes */
	 aputc(0, res);
   }

   putlong(res, 0);		/* Some mac specific thing I don't understand */
   aput_int16_be_checked(0,res);		/* another */
   aput_int16_be_checked(0,res);		/* another */

   aput_int16_be_checked(4+aftell(res)-rend,res);	/* Offset to resource types */
   aput_int16_be_checked(0,res);		/* Don't know where the names go yet */

   rtypesstart=aftell(res);
   for (i=0; rtypes[i].tag != 0; ++i);
   aput_int16_be_checked(i-1,res);	/* Count of different types */
   for (i=0; rtypes[i].tag != 0; ++i) {
      putlong(res, rtypes[i].tag);	/* Resource type */
      aput_int16_be_checked(0,res);		/* Number of resources of this type */
      aput_int16_be_checked(0,res);		/* Offset to the resource list */
   }

   /* Now the resource lists... */
   for (i=0; rtypes[i].tag != 0; ++i) {
      rtypes[i].resloc=aftell(res);
      for (j=0; rtypes[i].res[j].pos != 0; ++j) {
	 aput_int16_be_checked(rtypes[i].res[j].id,res);
	 rtypes[i].res[j].nameptloc=aftell(res);
	 aput_int16_be_checked(0xffff,res);	/* assume no name at first */
	 aputc(rtypes[i].res[j].flags, res);	/* resource flags */
	 /* three byte resource offset */
	 aputc(((rtypes[i].res[j].pos-resource_base) >> 16)&0xff, res);
	 aputc(((rtypes[i].res[j].pos-resource_base) >> 8)&0xff, res);
	 aputc(((rtypes[i].res[j].pos-resource_base)&0xff), res);
	 putlong(res, 0);
      }
   }
   namestart=aftell(res);
   /* Now the names, if any */
   for (i=0; rtypes[i].tag != 0; ++i) {
      for (j=0; rtypes[i].res[j].pos != 0; ++j) {
	 if (rtypes[i].res[j].name != NULL) {
	    rtypes[i].res[j].nameloc=aftell(res);
	    aputc(strlen(rtypes[i].res[j].name), res);	/* Length */
	    afwrite(rtypes[i].res[j].name, 1, strlen(rtypes[i].res[j].name),
		   res);
	 }
      }
   }
   mend=aftell(res);

   /* Repeat the rtypes list now we know where they go */
   afseek(res, rtypesstart+2, SEEK_SET);	/* skip over the count */
   for (i=0; rtypes[i].tag != 0; ++i) {
      putlong(res, rtypes[i].tag);	/* Resource type */
      for (j=0; rtypes[i].res[j].pos != 0; ++j);
      aput_int16_be_checked(j-1,res);	/* Number of resources of this type */
      aput_int16_be_checked(rtypes[i].resloc-rtypesstart,res);
   }
   /* And go back and fixup any name pointers */
   for (i=0; rtypes[i].tag != 0; ++i) {
      for (j=0; rtypes[i].res[j].pos != 0; ++j) {
	 if (rtypes[i].res[j].name != NULL) {
	    afseek(res, rtypes[i].res[j].nameptloc, SEEK_SET);
	    aput_int16_be_checked(rtypes[i].res[j].nameloc-namestart,res);
	 }
      }
   }

   afseek(res, rend, SEEK_SET);
   /* Fixup duplicate header (and offset to the name list) */
   if (format<ff_ttfdfont) {
      putlong(res, 0x100);	/* start of resource data */
      putlong(res, rend-rfork_base);	/* start of resource map */
      putlong(res, rend-rfork_base-0x100);	/* length of resource data */
      putlong(res, mend-rend);	/* length of map section */
   } else {
      for (i=0; i<16; ++i)
	 aputc(0, res);
   }

   putlong(res, 0);		/* Some mac specific thing I don't understand */
   aput_int16_be_checked(0,res);		/* another */
   aput_int16_be_checked(0,res);		/* another */

   aput_int16_be_checked(4+aftell(res)-rend,res);	/* Offset to resource types */
   aput_int16_be_checked(namestart-rend,res);	/* name section */

   afseek(res, rfork_base, SEEK_SET);
   /* Fixup main resource header */
   putlong(res, 0x100);		/* start of resource data */
   putlong(res, rend-rfork_base);	/* start of resource map */
   putlong(res, rend-rfork_base-0x100);	/* length of resource data */
   putlong(res, mend-rend);	/* length of map section */
}

long mactime(void) {
   time_t now;

   time(&now);
   /* convert from 1970 based time to 1904 based time */
   now +=
      (1970-1904)*365L*24*60*60 +
      ((1970-1904) >> 2)*24*60*60;
   /* Ignore any leap seconds -- Sorry Steve */
   return (now);
}

static int DumpMacBinaryHeader(AFILE *res,struct macbinaryheader *mb) {
   uint8_t header[128], *hpt;
   char buffer[256], *pt, *dpt;
   uint32_t len;
   time_t now;
   int crc;

   if (mb->macfilename==NULL) {
      char *pt=strrchr(mb->binfilename, '/');

      if (pt==NULL)
	 pt=mb->binfilename;
      else
	 ++pt;
      strncpy(buffer, pt, sizeof(buffer)-1);
      dpt=strrchr(buffer, '.');
      if (dpt==NULL) {
	 buffer[0]='_';
	 strcpy(buffer+1, pt);
      } else
	 *dpt='\0';
      mb->macfilename=buffer;
      buffer[63]='\0';
   }

   memset(header, '\0', sizeof(header));
   hpt=header;
   *hpt++='\0';		/* version number */
   /* Mac Filename */
   pt=mb->macfilename;
   *hpt++=strlen(pt);
   while (*pt)
      *hpt++=*pt++;
   while (hpt<header+65)
      *hpt++='\0';
   /* Mac File Type */
   *hpt++=mb->type >> 24;
   *hpt++=mb->type >> 16;
   *hpt++=mb->type >> 8;
   *hpt++=mb->type;
   /* Mac Creator */
   *hpt++=mb->creator >> 24;
   *hpt++=mb->creator >> 16;
   *hpt++=mb->creator >> 8;
   *hpt++=mb->creator;
   *hpt++='\0';		/* No finder flags set */
   *hpt++='\0';		/* (byte 74) MBZ */
   *hpt++='\0';
   *hpt++='\0';		/* Vert Position in folder */
   *hpt++='\0';
   *hpt++='\0';		/* Hor Position in folder */
   *hpt++='\0';
   *hpt++='\0';		/* window or folder id??? */
   *hpt++='\0';		/* protected bit ??? */
   *hpt++='\0';		/* (byte 82) MBZ */
   /* Data fork length */
   *hpt++='\0';
   *hpt++='\0';
   *hpt++='\0';
   *hpt++='\0';
   /* Resource fork length */
   afseek(res, 0, SEEK_END);
   len=aftell(res)-sizeof(header);
   *hpt++=len >> 24;
   *hpt++=len >> 16;
   *hpt++=len >> 8;
   *hpt++=len;
   /* Pad resource fork to be a multiple of 128 bytes */
   while ((len&127) != 0) {
      aputc('\0', res);
      ++len;
   }

   /* Creation time, (seconds from 1/1/1904) */
   now=mactime();
   time(&now);
   *hpt++=now >> 24;
   *hpt++=now >> 16;
   *hpt++=now >> 8;
   *hpt++=now;
   /* Modification time, (seconds from 1/1/1904) */
   *hpt++=now >> 24;
   *hpt++=now >> 16;
   *hpt++=now >> 8;
   *hpt++=now;

   *hpt++='\0';
   *hpt++='\0';		/* Get Info comment length */
   *hpt++=0;			/* More finder flags */

/* MacBinary 3 */
   memcpy(header+102, "mBIN", 4);
   header[106]=0;		/* Script. I assume 0 is latin */
   header[107]=0;		/* extended finder flags */
/* End of MacBinary 3 */
   header[122]=130;		/* MacBinary version 3, written in (129 is MB2) */
   header[123]=129;		/* MacBinary Version 2, needed to read */

   crc=binhex_crc(header, 124);
   header[124]=crc >> 8;
   header[125]=crc;

   afseek(res, 0, SEEK_SET);
   afwrite(header, 1, sizeof(header), res);
   return (true);
}

static void WriteDummyMacHeaders(AFILE *res) {
   /* Leave space for the mac binary header (128bytes) and the mac resource */
   /*  file header (256 bytes) */
   int i;

   for (i=0; i<128; ++i)
      aputc(0, res);
   for (i=0; i<256; ++i)
      aputc(0, res);
}

static void WriteDummyDFontHeaders(AFILE *res) {
   /* Leave space for the mac resource file header (256 bytes) */
   /*  dfonts have the format of a data fork resource file (which I've never */
   /*  seen documented, but appears to be just like a resource fork except */
   /*  the first 16 bytes are not duplicated at the map */
   int i;

   for (i=0; i<256; ++i)
      aputc(0, res);
}

	/* The mac has rules about what the filename should be for a postscript */
	/*  font. If you deviate from those rules the font will not be found */
	/*  The font name must begin with a capital letter */
	/*  The filename is designed by modifying the font name */
	/*  After the initial capital there can be at most 4 lower case letters (or digits) */
	/*   in the filename, any additional lc letters (or digits) in the fontname are ignored */
	/*  Every subsequent capital will be followed by at most 2 lc letters */
	/*  special characters ("-$", etc.) are removed entirely */
	/* So Times-Bold => TimesBol, HelveticaDemiBold => HelveDemBol */
	/* MacBinary limits the name to 63 characters, I dunno what happens if */
	/*  we excede that */
static void MakeMacPSName(char buffer[63],SplineFont *sf) {
   char *pt, *spt, *lcpt;

   for (pt=buffer, spt=sf->fontname; *spt && pt<buffer+63-1; ++spt) {
      if (isupper(*spt) || spt==sf->fontname) {
	 *pt++=*spt;
	 lcpt=(spt==sf->fontname?spt+5:spt+3);
      } else if ((islower(*spt) || isdigit(*spt)) && spt<lcpt)
	 *pt++=*spt;
   }
   *pt='\0';
}

int WriteMacPSFont(char *filename, SplineFont *sf, enum fontformat format,
		   int flags, EncMap * map, int layer) {
   AFILE *res, *temppfb;
   int ret=1;
   struct resourcetype resources[2];
   struct macbinaryheader header;
   int lcfn=false, lcfam=false;
   char buffer[63];

   temppfb=atmpfile();
   if (temppfb==NULL)
      return (0);

   /* The mac has rules about what the filename should be for a postscript */
   /*  font. If you deviate from those rules the font will not be found */
   /*  The font name must begin with a capital letter */
   /*  The filename is designed by modifying the font name */
   /*  After the initial capital there can be at most 4 lower case letters (or digits) */
   /*   in the filename, any additional lc letters (or digits) in the fontname are ignored */
   /*  Every subsequent capital will be followed by at most 2 lc letters */
   /*  special characters ("-$", etc.) are removed entirely */
   /* So Times-Bold => TimesBol, HelveticaDemiBold => HelveDemBol */
   /* MacBinary limits the name to 63 characters, I dunno what happens if */
   /*  we excede that */
   if (islower(*sf->fontname)) {
      *sf->fontname=toupper(*sf->fontname);
      lcfn=true;
   }
   if (islower(*sf->familyname)) {
      *sf->familyname=toupper(*sf->familyname);
      lcfam=true;
   }
   MakeMacPSName(buffer, sf);

   ret=_WritePSFont(temppfb, sf, ff_pfb, flags, map, NULL, layer);
   if (lcfn)
      *sf->fontname=tolower(*sf->fontname);
   if (lcfam)
      *sf->familyname=tolower(*sf->familyname);
   if (ret==0 || aferror(temppfb)) {
      afclose(temppfb);
      return (0);
   }

   res=afopen(filename, "wb+");
   if (res==NULL) {
      afclose(temppfb);
      return (0);
   }

   WriteDummyMacHeaders(res);
   memset(resources, '\0', sizeof(resources));
   afseek(temppfb,0,SEEK_SET);

   resources[0].tag=CHR('P', 'O', 'S', 'T');
   resources[0].res=PSToResources(res, temppfb);
   afclose(temppfb);
   DumpResourceMap(res, resources, format);
   free(resources[0].res);

   header.macfilename=buffer;
   /* Adobe uses a creator of ASPF (Adobe Systems PostScript Font I assume) */
   /* Fontographer uses ACp1 (Altsys Corp. PostScript type 1???) */
   /* Both include an FREF, BNDL, ICON* and comment */
   /* I shan't bother with that... It'll look ugly with no icon, but oh well */
   header.type=CHR('L', 'W', 'F', 'N');
   header.creator=CHR('G', 'W', 'p', '1');
   ret=DumpMacBinaryHeader(res, &header);
   if (aferror(res))
      ret=0;
   if (afclose(res)==-1)
      ret=0;
   return (ret);
}

int WriteMacTTFFont(char *filename, SplineFont *sf, enum fontformat format,
		    int32_t * bsizes, enum bitmapformat bf, int flags,
		    EncMap * map, int layer) {
   AFILE *res, *tempttf;
   int ret=1, r;
   struct resourcetype resources[4];
   struct resource rlist[3][2], *dummynfnts=NULL;
   struct macbinaryheader header;

   tempttf=atmpfile();
   if (tempttf==NULL)
      return (0);

   if (_WriteTTFFont(tempttf, sf, format==ff_none?ff_none :
		     format==ff_ttfmacbin?ff_ttf :
		     format-1, bsizes, bf, flags, map, layer)==0
       || aferror(tempttf)) {
      afclose(tempttf);
      return (0);
   }
   if (bf != bf_ttf && bf != bf_sfnt_dfont)
      bsizes=NULL;		/* as far as the FOND for the truetype is concerned anyway */

   res=afopen(filename, "wb+");
   if (res==NULL) {
      afclose(tempttf);
      return (0);
   }

   if (format != ff_ttfmacbin)
      WriteDummyDFontHeaders(res);
   else
      WriteDummyMacHeaders(res);
   memset(rlist, '\0', sizeof(rlist));
   memset(resources, '\0', sizeof(resources));
   afseek(tempttf,0,SEEK_SET);

   r=0;
   resources[r].tag=CHR('s', 'f', 'n', 't');
   resources[r++].res=rlist[0];
   rlist[0][0].pos=TTFToResource(res, tempttf);
   rlist[0][0].id=HashToId(sf->fontname, sf, map);
   rlist[0][0].flags=0x00;	/* sfnts generally have resource flags 0x20 */
   if (bsizes != NULL) {
      resources[r].tag=CHR('N', 'F', 'N', 'T');
      resources[r++].res=dummynfnts =
	 BuildDummyNFNTlist(res, sf, bsizes, rlist[0][0].id, map);
   }
   resources[r].tag=CHR('F', 'O', 'N', 'D');
   resources[r].res=rlist[1];
   rlist[1][0].pos=SFToFOND(res, sf, rlist[0][0].id, true, bsizes, map);
   rlist[1][0].flags=0x00;	/* I've seen FONDs with resource flags 0, 0x20, 0x60 */
   rlist[1][0].id=rlist[0][0].id;
   rlist[1][0].name=sf->fondname?sf->fondname:sf->familyname;
   afclose(tempttf);
   DumpResourceMap(res, resources, format);
   free(dummynfnts);

   ret=true;
   if (format==ff_ttfmacbin) {
      header.macfilename=NULL;
      header.binfilename=filename;
      /* Fontographer uses the old suitcase format for both bitmaps and ttf */
      header.type=CHR('F', 'F', 'I', 'L');
      header.creator=CHR('D', 'M', 'O', 'V');
      ret=DumpMacBinaryHeader(res, &header);
   }
   if (aferror(res))
      ret=false;
   if (afclose(res)==-1)
      ret=0;
   return (ret);
}

int WriteMacBitmaps(char *filename, SplineFont *sf, int32_t * sizes,
		    int is_dfont, EncMap * map) {
   AFILE *res;
   int ret=1;
   struct resourcetype resources[3];
   struct resource rlist[2][2];
   struct macbinaryheader header;
   char *binfilename, *pt, *dpt;

   /* The filename we've been given is for the outline font, which might or */
   /*  might not be stuffed inside a bin file */
   binfilename=malloc(strlen(filename)+strlen(".bmap.dfont")+1);
   strcpy(binfilename, filename);
   pt=strrchr(binfilename, '/');
   if (pt==NULL)
      pt=binfilename;
   else
      ++pt;
   dpt=strrchr(pt, '.');
   if (dpt==NULL)
      dpt=pt+strlen(pt);
   else if (strmatch(dpt, ".bin")==0 || strmatch(dpt, ".dfont")==0) {
      *dpt='\0';
      dpt=strrchr(pt, '.');
      if (dpt==NULL)
	 dpt=pt+strlen(pt);
   }
   strcpy(dpt, is_dfont?".bmap.dfont":".bmap.bin");

   res=afopen(binfilename, "wb+");
   if (res==NULL) {
      free(binfilename);
      return (0);
   }

   if (is_dfont)
      WriteDummyDFontHeaders(res);
   else
      WriteDummyMacHeaders(res);
   memset(rlist, '\0', sizeof(rlist));
   memset(resources, '\0', sizeof(resources));

   resources[0].tag=CHR('N', 'F', 'N', 'T');
   resources[0].res=SFToNFNTs(res, sf, sizes, map);
   resources[1].tag=CHR('F', 'O', 'N', 'D');
   resources[1].res=rlist[1];
   rlist[1][0].id=HashToId(sf->fontname, sf, map);
   rlist[1][0].pos=SFToFOND(res, sf, rlist[1][0].id, false, sizes, map);
   rlist[1][0].name=sf->fondname?sf->fondname:sf->familyname;
   DumpResourceMap(res, resources, is_dfont?ff_ttfdfont:ff_ttfmacbin);

   ret=true;
   if (!is_dfont) {
      header.macfilename=NULL;
      header.binfilename=binfilename;
      /* Fontographer uses the old suitcase format for both bitmaps and ttf */
      header.type=CHR('F', 'F', 'I', 'L');
      header.creator=CHR('D', 'M', 'O', 'V');
      ret=DumpMacBinaryHeader(res, &header);
   }
   if (aferror(res))
      ret=false;
   if (afclose(res)==-1)
      ret=0;
   free(resources[0].res);
   free(binfilename);
   return (ret);
}

/* We have to worry about these font formats:
  ff_pfbmacbin, ff_ttfmacbin, ff_ttfdfont, ff_otfdfont, ff_otfciddfont, ff_none
  bf_ttf, bf_sfnt_dfont, bf_nfntmacbin,
  bf_nfntdfont	I no long support this. OS/X doesn't support NFNTs so there's no point
*/

int WriteMacFamily(char *filename, struct sflist *sfs, enum fontformat format,
		   enum bitmapformat bf, int flags, int layer) {
   AFILE *res;
   int ret=1, r, i;
   struct resourcetype resources[4];
   struct resource *rlist;
   struct macbinaryheader header;
   struct sflist *sfi, *sfsub;
   char buffer[80];
   int freefilename=0;
   char *pt;
   int id, fondcnt;
   struct sflistlist *sfsl, *sfli;

   if (format==ff_pfbmacbin) {
      for (sfi=sfs; sfi != NULL; sfi=sfi->next) {
	 char *tempname;

	 MakeMacPSName(buffer, sfi->sf);
	 strcat(buffer, ".bin");
	 tempname=malloc(strlen(filename)+strlen(buffer)+1);
	 strcpy(tempname, filename);
	 pt=strrchr(tempname, '/');
	 if (pt==NULL)
	    pt=tempname-1;
	 strcpy(pt+1, buffer);
	 if (strcmp(tempname, filename)==0) {
	    char *tf=malloc(strlen(filename)+20);

	    strcpy(tf, filename);
	    filename=tf;
	    freefilename=true;
	    pt=strrchr(filename, '.');
	    if (pt==NULL || pt<strrchr(filename, '/'))
	       pt=filename+strlen(filename)+1;
	    strcpy(pt-1, ".fam.bin");
	 }
	 if (WriteMacPSFont(tempname, sfi->sf, format, flags, sfi->map, layer)
	    ==0)
	    return (0);
	 free(tempname);
      }
   } else if (format != ff_none || bf==bf_sfnt_dfont) {
      for (sfi=sfs; sfi != NULL; sfi=sfi->next) {
	 sfi->tempttf=atmpfile();
	 if (sfi->tempttf==NULL ||
	     _WriteTTFFont(sfi->tempttf, sfi->sf,
			   format==ff_none?ff_none:format ==
			   ff_ttfmacbin?ff_ttf:format-1, sfi->sizes, bf,
			   flags, sfi->map, layer)==0
	     || aferror(sfi->tempttf)) {
	    for (sfsub=sfs; sfsub != sfi; sfsub=sfsub->next)
	       afclose(sfsub->tempttf);
	    return (0);
	 }
	 afseek(sfi->tempttf,0,SEEK_SET);
      }
   }

   res=afopen(filename, "wb+");
   if (res==NULL) {
      for (sfsub=sfs; sfsub != NULL; sfsub=sfsub->next)
	 afclose(sfsub->tempttf);
      return (0);
   }

   if (format==ff_ttfdfont || format==ff_otfdfont
       || format==ff_otfciddfont
       || bf==bf_sfnt_dfont /*|| (format==ff_none && bf==bf_nfntdfont) */ )
      WriteDummyDFontHeaders(res);
   else
      WriteDummyMacHeaders(res);
   memset(resources, '\0', sizeof(resources));

   id=HashToId(sfs->sf->fontname, sfs->sf, sfs->map);

   r=0;
   if (format==ff_ttfmacbin || format==ff_ttfdfont
       || format==ff_otfdfont || format==ff_otfciddfont
       || (format==ff_none && bf==bf_sfnt_dfont)) {
      resources[r].tag=CHR('s', 'f', 'n', 't');
      for (sfi=sfs, i=0; sfi != NULL; sfi=sfi->next, ++i);
      resources[r].res=calloc(i+1, sizeof(struct resource));
      for (sfi=sfs, i=0; sfi != NULL; sfi=sfi->next, ++i) {
	 resources[r].res[i].pos=TTFToResource(res, sfi->tempttf);
	 resources[r].res[i].id=sfi->id=id+i;
	 resources[r].res[i].flags=0x00;	/* sfnts generally have resource flags 0x20 */
	 afclose(sfi->tempttf);
      }
      ++r;
      if (bf==bf_ttf || bf==bf_sfnt_dfont) {
	 resources[r].tag=CHR('N', 'F', 'N', 'T');
	 resources[r++].res=BuildDummyNFNTfamilyList(res, sfs, id);
      }
   }
   if (bf==bf_nfntmacbin /*|| bf==bf_nfntdfont */ ) {
      resources[r].tag=CHR('N', 'F', 'N', 'T');
      resources[r++].res=SFsToNFNTs(res, sfs, id);
   }

   sfsl=FondSplitter(sfs, &fondcnt);
   rlist=calloc(fondcnt+1, sizeof(struct resource));
   resources[r].tag=CHR('F', 'O', 'N', 'D');
   resources[r++].res=rlist;
   for (i=0, sfli=sfsl; i<fondcnt && sfli != NULL;
	++i, sfli=sfli->next) {
      rlist[i].pos=SFsToFOND(res, sfli->sfs, id, format, bf);
      rlist[i].flags=0x00;	/* I've seen FONDs with resource flags 0, 0x20, 0x60 */
      rlist[i].id=id+i;
      rlist[i].name=sfli->fondname;
   }
   DumpResourceMap(res, resources, format != ff_none?format :
		   bf==bf_nfntmacbin?ff_ttfmacbin:ff_ttfdfont);
   SFListListFree(sfsl);
   for (i=0; i<r; ++i)
      free(resources[i].res);

   ret=true;
   if (format==ff_ttfmacbin || format==ff_pfbmacbin ||
       (format==ff_none && bf==bf_nfntmacbin)) {
      header.macfilename=NULL;
      header.binfilename=filename;
      /* Fontographer uses the old suitcase format for both bitmaps and ttf */
      header.type=CHR('F', 'F', 'I', 'L');
      header.creator=CHR('D', 'M', 'O', 'V');
      ret=DumpMacBinaryHeader(res, &header);
   }
   if (aferror(res))
      ret=false;
   if (afclose(res)==-1)
      ret=0;
   if (freefilename)
      free(filename);
   for (sfi=sfs; sfi != NULL; sfi=sfi->next) {
      free(sfi->ids);
      free(sfi->bdfs);
   }
   return (ret);
}

/* ******************************** Reading ********************************* */

static SplineFont *SearchPostScriptResources(AFILE *f,long rlistpos,
					     int subcnt, long rdata_pos,
					     long name_list, int flags) {
   long here=aftell(f);
   long *offsets, lenpos;
   int rname=-1, tmp;
   int ch1, ch2;
   int len, type, i, j, rlen;
   unsigned short id, *rsrcids;

   /* I don't pretend to understand the rational behind the format of a */
   /*  postscript font. It appears to be split up into chunks where the */
   /*  maximum chunk size is 0x800, each section (ascii, binary, ascii, eof) */
   /*  has its own set of chunks (ie chunks don't cross sections) */
   char *buffer=NULL;
   int max=0;
   AFILE *pfb;
   FontDict *fd;
   SplineFont *sf;

   afseek(f, rlistpos, SEEK_SET);
   rsrcids=calloc(subcnt, sizeof(short));
   offsets=calloc(subcnt, sizeof(long));
   for (i=0; i<subcnt; ++i) {
      rsrcids[i]=aget_uint16_be(f);
      tmp=(short) aget_uint16_be(f);
      if (rname==-1)
	 rname=tmp;
      /* flags=*/ agetc(f);
      ch1=agetc(f);
      ch2=agetc(f);
      offsets[i]=rdata_pos+((ch1 << 16)|(ch2 << 8)|agetc(f));
      /* mbz=*/ aget_int32_be(f);
   }

   pfb=atmpfile();
   if (pfb==NULL) {
      ErrorMsg(2,"Can't open temporary file for postscript output\n");
      afseek(f, here, SEEK_SET);
      free(offsets);
      return (NULL);
   }

   aputc(0x80, pfb);
   aputc(1, pfb);
   lenpos=aftell(pfb);
   aputc(0, pfb);
   aputc(0, pfb);
   aputc(0, pfb);
   aputc(0, pfb);
   len=0;
   type=1;
   id=501;
   for (i=0; i<subcnt; ++i) {
      for (j=0; j<subcnt; ++j)
	 if (rsrcids[j]==id)
	    break;
      if (j==subcnt) {
	 ErrorMsg(2,"Missing POST resource %u\n", id);
	 break;
      }
      id=id+1;
      afseek(f, offsets[j], SEEK_SET);
      rlen=aget_int32_be(f);
      ch1=agetc(f);
      ch2=agetc(f);
      rlen -= 2;		/* those two bytes don't count as real data */
      if (ch1==type)
	 len += rlen;
      else {
	 long hold=aftell(pfb);

	 afseek(pfb, lenpos, SEEK_SET);
	 aputc(len >> 24, pfb);
	 aputc((len >> 16)&0xff, pfb);
	 aputc((len >> 8)&0xff, pfb);
	 aputc(len&0xff, pfb);
	 afseek(pfb, hold, SEEK_SET);
	 if (ch1==5)		/* end of font mark */
	    break;
	 aputc(0x80, pfb);
	 aputc(ch1, pfb);
	 lenpos=aftell(pfb);
	 aputc(0, pfb);
	 aputc(0, pfb);
	 aputc(0, pfb);
	 aputc(0, pfb);
	 type=ch1;
	 len=rlen;
      }
      if (rlen>max) {
	 free(buffer);
	 max=rlen;
	 if (max<0x800)
	    max=0x800;
	 buffer=malloc(max);
	 if (buffer==NULL) {
	    ErrorMsg(3,"Out of memory\n");
	    exit(1);
	 }
      }
      afread(buffer, 1, rlen, f);
      afwrite(buffer, 1, rlen, pfb);
   }
   free(buffer);
   free(offsets);
   free(rsrcids);
   aputc(0x80, pfb);
   aputc(3, pfb);
   afseek(pfb, lenpos, SEEK_SET);
   aputc(len >> 24, pfb);
   aputc((len >> 16)&0xff, pfb);
   aputc((len >> 8)&0xff, pfb);
   aputc(len&0xff, pfb);
   afseek(f, here, SEEK_SET);
   afseek(pfb,0,SEEK_SET);
   if (flags&ttf_onlynames)
      return ((SplineFont *) _NamesReadPostScript(pfb));	/* This closes the font for us */

   fd=_ReadPSFont(pfb);
   sf=NULL;
   if (fd != NULL) {
      sf=SplineFontFromPSFont(fd);
      PSFontFree(fd);
      /* There is no FOND in a postscript file, so we can't read any kerning */
   }
   afclose(pfb);
   return (sf);
}

static SplineFont *SearchTtfResources(AFILE *f,long rlistpos,int subcnt,
				      long rdata_pos, long name_list,
				      char *filename, int flags,
				      enum openflags openflags) {
   long here, start=aftell(f);
   long roff;
   int rname=-1;
   int ch1, ch2;
   int len, i, rlen, ilen;

   /* The sfnt resource is just a copy of the ttf file */
   char *buffer=NULL;
   int max=0;
   AFILE *ttf;
   SplineFont *sf;
   int which=0;
   char **names;
   char *pt, *lparen, *rparen;
   char *chosenname=NULL;

   afseek(f, rlistpos, SEEK_SET);
   if (subcnt>1 || (flags&ttf_onlynames)) {
      names=calloc(subcnt+1, sizeof(char *));
      for (i=0; i<subcnt; ++i) {
	 /* resource id=*/ aget_uint16_be(f);
	 /* rname=(short) */ aget_uint16_be(f);
	 /* flags=*/ agetc(f);
	 ch1=agetc(f);
	 ch2=agetc(f);
	 roff=rdata_pos+((ch1 << 16)|(ch2 << 8)|agetc(f));
	 /* mbz=*/ aget_int32_be(f);
	 here=aftell(f);
	 names[i]=TTFGetFontName(f, roff+4, roff+4);
	 if (names[i]==NULL) {
	    char buffer[32];

	    sprintf(buffer, "Nameless%d", i);
	    names[i]=fastrdup(buffer);
	 }
	 afseek(f, here, SEEK_SET);
      }
      if (flags&ttf_onlynames) {
	 return ((SplineFont *) names);
      }
      if ((pt=strrchr(filename, '/'))==NULL)
	 pt=filename;
      /* Someone gave me a font "Nafees Nastaleeq(Updated).ttf" and complained */
      /*  that ff wouldn't open it */
      /* Now someone will complain about "Nafees(Updated).ttc(fo(ob)ar)" */
      if ((lparen=strrchr(pt, '(')) != NULL &&
	  (rparen=strrchr(lparen, ')')) != NULL && rparen[1]=='\0') {
	 char *find=fastrdup(lparen+1);

	 pt=strchr(find, ')');
	 if (pt != NULL)
	    *pt='\0';
	 for (which=subcnt-1; which >= 0; --which)
	    if (strcmp(names[which], find)==0)
	       break;
	 if (which==-1) {
	    char *end;

	    which=strtol(find, &end, 10);
	    if (*end != '\0')
	       which=-1;
	 }
	 if (which==-1) {
	    char *fn=fastrdup(filename);

	    fn[lparen-filename]='\0';
	    ErrorMsg(2,"Not in collection:  %s is not in %.100s\n",find,fn);
	    free(fn);
	 }
	 free(find);
      } else
	which=0;
      if (lparen==NULL && which != -1)
	 chosenname=fastrdup(names[which]);
      for (i=0; i<subcnt; ++i)
	 free(names[i]);
      free(names);
      afseek(f, rlistpos, SEEK_SET);
   }

   for (i=0; i<subcnt; ++i) {
      /* resource id=*/ aget_uint16_be(f);
      rname=(short) aget_uint16_be(f);
      /* flags=*/ agetc(f);
      ch1=agetc(f);
      ch2=agetc(f);
      roff=rdata_pos+((ch1 << 16)|(ch2 << 8)|agetc(f));
      /* mbz=*/ aget_int32_be(f);
      if (i != which)
	 continue;
      here=aftell(f);

      ttf=atmpfile();
      if (ttf==NULL) {
	 ErrorMsg(2,"Can't open temporary file for truetype output.\n");
	 continue;
      }

      afseek(f, roff, SEEK_SET);
      ilen=rlen=aget_int32_be(f);
      if (rlen>16*1024)
	 ilen=16*1024;
      if (ilen>max) {
	 free(buffer);
	 max=ilen;
	 if (max<0x800)
	    max=0x800;
	 buffer=malloc(max);
      }
      for (len=0; len<rlen;) {
	 int temp=ilen;

	 if (rlen-len<ilen)
	    temp=rlen-len;
	 temp=afread(buffer, 1, temp, f);
	 if (temp==EOF)
	    break;
	 afwrite(buffer, 1, temp, ttf);
	 len += temp;
      }
      afseek(ttf,0,SEEK_SET);
      sf=_SFReadTTF(ttf, flags, openflags, NULL, NULL);
      afclose(ttf);
      if (sf != NULL) {
	 free(buffer);
	 afseek(f, start, SEEK_SET);
	 if (sf->chosenname==NULL)
	    sf->chosenname=chosenname;
	 return (sf);
      }
      afseek(f, here, SEEK_SET);
   }
   free(chosenname);
   free(buffer);
   afseek(f, start, SEEK_SET);
   return (NULL);
}

struct assoc {
   short size, style, id;
   /* size==0 => scalable */
   /* style>>8 is the bit depth (0=>1, 1=>2, 2=>4, 3=>8) */
   /* search order for ID is sfnt, NFNT, FONT */
};

struct stylewidths {
   short style;
   short *widthtab;		/* 4.12 fixed number with the width specified as a fraction of an em */
};

struct kerns {
   unsigned char ch1, ch2;
   short offset;		/* 4.12 */
};

struct stylekerns {
   short style;
   int kernpairs;
   struct kerns *kerns;
};

typedef struct fond {
   char *fondname;
   int first, last;
   int assoc_cnt;
   struct assoc *assoc;
   int stylewidthcnt;
   struct stylewidths *stylewidths;
   int stylekerncnt;
   struct stylekerns *stylekerns;
   char *psnames[48];
   struct fond *next;
} FOND;

struct MacFontRec {
   short fontType;
   short firstChar;
   short lastChar;
   short widthMax;
   short kernMax;		/* bb learing */
   short Descent;		/* maximum negative distance below baseline */
   short fRectWidth;		/* bounding box width */
   short fRectHeight;		/* bounding box height */
   unsigned short *offsetWidths;	/* offset to start of offset/width table */
   /* 0xffff => undefined, else high byte is offset in locTable, */
   /*  low byte is width */
   short ascent;
   short descent;
   short leading;
   short rowWords;		/* shorts per row */
   unsigned short *fontImage;	/* rowWords*fRectHeight */
   /* Images for all characters plus one extra for undefined */
   unsigned short *locs;	/* lastchar-firstchar+3 words */
   /* Horizontal offset to start of n'th character. Note: applies */
   /*  to each row. Missing characters have same loc as following */
};

static void FondListFree(FOND *list) {
   FOND *next;
   int i;

   while (list != NULL) {
      next=list->next;
      free(list->assoc);
      for (i=0; i<list->stylewidthcnt; ++i)
	 free(list->stylewidths[i].widthtab);
      free(list->stylewidths);
      for (i=0; i<list->stylekerncnt; ++i)
	 free(list->stylekerns[i].kerns);
      free(list->stylekerns);
      for (i=0; i<48; ++i)
	 free(list->psnames[i]);
      free(list);
      list=next;
   }
}

/* There's probably only one fond in the file, but there could be more so be */
/*  prepared... */
/* I want the fond: */
/*  to get the fractional widths for the SWIDTH entry on bdf */
/*  to get the font name */
/*  to get the font association tables */
/*  to get the style flags */
/* http://developer.apple.com/techpubs/mac/Text/Text-269.html */
static FOND *BuildFondList(AFILE *f,long rlistpos,int subcnt,
			   long rdata_pos, long name_list, int flags) {
   long here, start=aftell(f);
   long offset;
   int rname=-1;
   char name[300];
   int ch1, ch2;
   int i, j, k, cnt, isfixed;
   FOND *head=NULL, *cur;
   long widoff, kernoff, styleoff;

   afseek(f, rlistpos, SEEK_SET);
   for (i=0; i<subcnt; ++i) {
      /* resource id=*/ aget_uint16_be(f);
      rname=(short) aget_uint16_be(f);
      /* flags=*/ agetc(f);
      ch1=agetc(f);
      ch2=agetc(f);
      offset=rdata_pos+((ch1 << 16)|(ch2 << 8)|agetc(f));
      /* mbz=*/ aget_int32_be(f);
      here=aftell(f);

      cur=calloc(1, sizeof(FOND));
      cur->next=head;
      head=cur;

      if (rname != -1) {
	 afseek(f, name_list+rname, SEEK_SET);
	 ch1=agetc(f);
	 afread(name, 1, ch1, f);
	 name[ch1]='\0';
	 cur->fondname=fastrdup(name);
      }

      offset += 4;
      afseek(f, offset, SEEK_SET);
      isfixed=aget_uint16_be(f)&0x8000?1:0;
      /* family id=*/ aget_uint16_be(f);
      cur->first=aget_uint16_be(f);
      cur->last=aget_uint16_be(f);
/* on a 1 point font... */
      /* ascent=*/ aget_uint16_be(f);
      /* descent=(short) */ aget_uint16_be(f);
      /* leading=*/ aget_uint16_be(f);
      /* widmax=*/ aget_uint16_be(f);
      if ((widoff=aget_int32_be(f)) != 0)
	 widoff += offset;
      if ((kernoff=aget_int32_be(f)) != 0)
	 kernoff += offset;
      if ((styleoff=aget_int32_be(f)) != 0)
	 styleoff += offset;
      for (j=0; j<9; ++j)
	 aget_uint16_be(f);
      /* internal&undefined, for international scripts=*/ aget_int32_be(f);
      /* version=*/ aget_uint16_be(f);
      cur->assoc_cnt=aget_uint16_be(f)+1;
      cur->assoc=calloc(cur->assoc_cnt, sizeof(struct assoc));
      for (j=0; j<cur->assoc_cnt; ++j) {
	 cur->assoc[j].size=aget_uint16_be(f);
	 cur->assoc[j].style=aget_uint16_be(f);
	 cur->assoc[j].id=aget_uint16_be(f);
      }
      if (widoff != 0) {
	 afseek(f, widoff, SEEK_SET);
	 cnt=aget_uint16_be(f)+1;
	 cur->stylewidthcnt=cnt;
	 cur->stylewidths=calloc(cnt, sizeof(struct stylewidths));
	 for (j=0; j<cnt; ++j) {
	    cur->stylewidths[j].style=aget_uint16_be(f);
	    cur->stylewidths[j].widthtab =
	       malloc((cur->last-cur->first+3)*sizeof(short));
	    for (k=cur->first; k <= cur->last+2; ++k)
	       cur->stylewidths[j].widthtab[k]=aget_uint16_be(f);
	 }
      }
      if (kernoff != 0 && (flags&ttf_onlykerns)) {
	 afseek(f, kernoff, SEEK_SET);
	 cnt=aget_uint16_be(f)+1;
	 cur->stylekerncnt=cnt;
	 cur->stylekerns=calloc(cnt, sizeof(struct stylekerns));
	 for (j=0; j<cnt; ++j) {
	    cur->stylekerns[j].style=aget_uint16_be(f);
	    cur->stylekerns[j].kernpairs=aget_uint16_be(f);
	    cur->stylekerns[j].kerns =
	       malloc(cur->stylekerns[j].kernpairs * sizeof(struct kerns));
	    for (k=0; k<cur->stylekerns[j].kernpairs; ++k) {
	       cur->stylekerns[j].kerns[k].ch1=agetc(f);
	       cur->stylekerns[j].kerns[k].ch2=agetc(f);
	       cur->stylekerns[j].kerns[k].offset=aget_uint16_be(f);
	    }
	 }
      }
      if (styleoff != 0) {
	 uint8_t stringoffsets[48];
	 int strcnt, stringlen, format;
	 char **strings, *pt;

	 afseek(f, styleoff, SEEK_SET);
	 /* class=*/ aget_uint16_be(f);
	 /* glyph encoding offset=*/ aget_int32_be(f);
	 /* reserved=*/ aget_int32_be(f);
	 for (j=0; j<48; ++j)
	    stringoffsets[j]=agetc(f);
	 strcnt=aget_uint16_be(f);
	 strings=malloc(strcnt * sizeof(char *));
	 for (j=0; j<strcnt; ++j) {
	    stringlen=agetc(f);
	    strings[j]=malloc(stringlen+2);
	    strings[j][0]=stringlen;
	    strings[j][stringlen+1]='\0';
	    for (k=0; k<stringlen; ++k)
	       strings[j][k+1]=agetc(f);
	 }
	 for (j=0; j<48; ++j) {
	    for (k=j-1; k >= 0; --k)
	       if (stringoffsets[j]==stringoffsets[k])
		  break;
	    if (k != -1)
	       continue;	/* this style doesn't exist */
	    format=stringoffsets[j]-1;
	    stringlen=strings[0][0];
	    if (format != 0)
	       for (k=0; k<strings[format][0]; ++k)
		  stringlen += strings[strings[format][k+1]-1][0];
	    pt=cur->psnames[j]=malloc(stringlen+1);
	    strcpy(pt, strings[0]+1);
	    pt += strings[0][0];
	    if (format != 0)
	       for (k=0; k<strings[format][0]; ++k) {
		  strcpy(pt, strings[strings[format][k+1]-1]+1);
		  pt += strings[strings[format][k+1]-1][0];
	       }
	    *pt='\0';
	 }
	 for (j=0; j<strcnt; ++j)
	    free(strings[j]);
	 free(strings);
      }
      afseek(f, here, SEEK_SET);
   }
   afseek(f, start, SEEK_SET);
   return (head);
}

static BDFChar *NFNTCvtBitmap(struct MacFontRec *font,int index,
			      SplineFont *sf, int gid) {
   BDFChar *bdfc;
   int i, j, bits, bite, bit;

   bdfc=chunkalloc(sizeof(BDFChar));
   memset(bdfc, '\0', sizeof(BDFChar));
   bdfc->xmin=(font->offsetWidths[index] >> 8)+font->kernMax;
   bdfc->xmax=bdfc->xmin+font->locs[index+1]-font->locs[index]-1;
   if (bdfc->xmax<bdfc->xmin)
      bdfc->xmax=bdfc->xmin;	/* Empty glyph mark */
   bdfc->ymin=-font->descent;
   bdfc->ymax=font->ascent-1;
   bdfc->width=font->offsetWidths[index]&0xff;
   bdfc->vwidth=font->ascent+font->descent;
   bdfc->bytes_per_line=((bdfc->xmax-bdfc->xmin) >> 3)+1;
   bdfc->bitmap =
      calloc(bdfc->bytes_per_line * font->fRectHeight, sizeof(uint8_t));
   bdfc->orig_pos=gid;
   bdfc->sc=sf->glyphs[gid];

   bits=font->locs[index];
   bite=font->locs[index+1];
   for (i=0; i<font->fRectHeight; ++i) {
      uint16_t *test=font->fontImage+i * font->rowWords;
      uint8_t *bpt=bdfc->bitmap+i * bdfc->bytes_per_line;

      for (bit=bits, j=0; bit<bite; ++bit, ++j) {
	 if (test[bit >> 4]&(0x8000 >> (bit&0xf)))
	    bpt[j >> 3] |= (0x80 >> (j&7));
      }
   }
   BCCompressBitmap(bdfc);
   return (bdfc);
}

static void LoadNFNT(AFILE *f,long offset,SplineFont *sf,int size) {
   long here=aftell(f);
   long baseow;
   long ow;
   int i, gid;
   struct MacFontRec font;
   BDFFont *bdf;
   SplineChar *sc;

   offset += 4;			/* skip over the length */
   afseek(f, offset, SEEK_SET);
   memset(&font, '\0', sizeof(struct MacFontRec));
   font.fontType=aget_uint16_be(f);
   font.firstChar=aget_uint16_be(f);
   font.lastChar=aget_uint16_be(f);
   font.widthMax=aget_uint16_be(f);
   font.kernMax=(short) aget_uint16_be(f);
   font.Descent=(short) aget_uint16_be(f);
   font.fRectWidth=aget_uint16_be(f);
   font.fRectHeight=aget_uint16_be(f);
   baseow=aftell(f);
   ow=aget_uint16_be(f);
   font.ascent=aget_uint16_be(f);
   font.descent=aget_uint16_be(f);
   if (font.Descent >= 0) {
      ow |= (font.Descent << 16);
      font.Descent=-font.descent;	/* Possibly overkill, but should be safe */
   }
   font.leading=aget_uint16_be(f);
   font.rowWords=aget_uint16_be(f);
   if (font.rowWords != 0) {
      font.fontImage =
	 calloc(font.rowWords * font.fRectHeight, sizeof(short));
      font.locs=calloc(font.lastChar-font.firstChar+3, sizeof(short));
      font.offsetWidths =
	 calloc(font.lastChar-font.firstChar+3, sizeof(short));
      for (i=0; i<font.rowWords * font.fRectHeight; ++i)
	 font.fontImage[i]=aget_uint16_be(f);
      for (i=0; i<font.lastChar-font.firstChar+3; ++i)
	 font.locs[i]=aget_uint16_be(f);
      afseek(f, baseow+2*ow, SEEK_SET);
      for (i=0; i<font.lastChar-font.firstChar+3; ++i)
	 font.offsetWidths[i]=aget_uint16_be(f);
   }
   afseek(f, here, SEEK_SET);
   if (font.rowWords==0)
      return;

   /* Now convert the FONT record to one of my BDF structs */
   bdf=calloc(1, sizeof(BDFFont));
   bdf->sf=sf;
   bdf->next=sf->bitmaps;
   sf->bitmaps=bdf;
   bdf->glyphcnt=bdf->glyphmax=sf->glyphcnt;
   bdf->pixelsize=font.ascent+font.descent;
   bdf->glyphs=calloc(sf->glyphcnt, sizeof(BDFChar *));
   bdf->ascent=font.ascent;
   bdf->descent=font.descent;
   bdf->res=72;
   for (i=font.firstChar; i <= font.lastChar+1; ++i) {
      if (i != font.lastChar+1)
	 sc=SFMakeChar(sf, sf->map, i);
      else {
	 sc=SFGetChar(sf, -1, ".notdef");
	 if (sc==NULL)
	    break;
      }
      gid=sc->orig_pos;
      bdf->glyphs[gid]=NFNTCvtBitmap(&font, i-font.firstChar, sf, gid);
      if (!sf->glyphs[gid]->widthset) {
	 sf->glyphs[gid]->width =
	    bdf->glyphs[gid]->width * (sf->ascent +
				       sf->descent)/bdf->pixelsize;
	 sf->glyphs[gid]->widthset=true;
      }
   }

   free(font.fontImage);
   free(font.locs);
   free(font.offsetWidths);
}

static char *BuildName(char *family,int style) {
   char buffer[350];

   strncpy(buffer, family, 200);
   if (style != 0)
      strcat(buffer, "-");
   if (style&sf_bold)
      strcat(buffer, "Bold");
   if (style&sf_italic)
      strcat(buffer, "Italic");
   if (style&sf_underline)
      strcat(buffer, "Underline");
   if (style&sf_outline)
      strcat(buffer, "Outline");
   if (style&sf_shadow)
      strcat(buffer, "Shadow");
   if (style&sf_condense)
      strcat(buffer, "Condensed");
   if (style&sf_extend)
      strcat(buffer, "Extended");
   return (fastrdup(buffer));
}

static int GuessStyle(char *fontname,int *styles,int style_cnt) {
   int which, style;
   char *stylenames=_GetModifiers(fontname, NULL, NULL);

   style=_MacStyleCode(stylenames, NULL, NULL);
   for (which=style_cnt; which >= 0; --which)
      if (styles[which]==style)
	 return (which);

   return (-1);
}

static FOND *PickFOND(FOND *fondlist,char *filename,char **name,
		      int *style) {
   int i, j;
   FOND *test;
   uint8_t stylesused[96];
   char **names;
   FOND **fonds, *fond;
   int *styles;
   int cnt, which;
   char *pt, *lparen;
   char *find=NULL;

   if ((pt=strrchr(filename, '/')) != NULL)
      pt=filename;
   if ((lparen=strchr(filename, '(')) != NULL
       && strchr(lparen, ')') != NULL) {
      find=fastrdup(lparen+1);
      pt=strchr(find, ')');
      if (pt != NULL)
	 *pt='\0';
      for (test=fondlist; test != NULL; test=test->next) {
	 for (i=0; i<48; ++i)
	    if (test->psnames[i] != NULL
		&& strcmp(find, test->psnames[i])==0) {
	       *style=(i&3)|((i&~3) << 1);	/* PS styles skip underline bit */
	       *name=fastrdup(test->psnames[i]);
	       return (test);
	    }
      }
   }

   /* The file may contain multiple families, and each family may contain */
   /*  multiple styles (and each style may contain multiple sizes, but that's */
   /*  not an issue for us here) */
   names=NULL;
   for (i=0; i<2; ++i) {
      cnt=0;
      for (test=fondlist; test != NULL; test=test->next)
	 if (test->fondname != NULL) {
	    memset(stylesused, 0, sizeof(stylesused));
	    for (j=0; j<test->assoc_cnt; ++j) {
	       if (test->assoc[j].size != 0
		   && !stylesused[test->assoc[j].style]) {
		  stylesused[test->assoc[j].style]=true;
		  if (names != NULL) {
		     names[cnt] =
			BuildName(test->fondname, test->assoc[j].style);
		     styles[cnt]=test->assoc[j].style;
		     fonds[cnt]=test;
		  }
		  ++cnt;
	       }
	    }
	 }
      if (names==NULL) {
	 names=calloc(cnt+1, sizeof(char *));
	 fonds=malloc(cnt * sizeof(FOND *));
	 styles=malloc(cnt * sizeof(int));
      }
   }

   if (find != NULL) {
      for (which=cnt-1; which >= 0; --which)
	 if (strcmp(names[which], find)==0)
	    break;
      if (which==-1 && strstrmatch(find, test->fondname) != NULL)
	 which=GuessStyle(find, styles, cnt);
      if (which==-1) {
	 char *fn=fastrdup(filename);

	 fn[lparen-filename]='\0';
	    ErrorMsg(2,"Not in collection:  %s is not in %.100s\n",find,fn);
	 free(fn);
      }
      free(find);
   } else if (cnt==1)
      which=0;
   else
      which=0;

   if (which != -1) {
      fond=fonds[which];
      *name=fastrdup(names[which]);
      *style=styles[which];
   }
   for (i=0; i<cnt; ++i)
      free(names[i]);
   free(names);
   free(fonds);
   free(styles);
   if (which==-1)
      return (NULL);

   return (fond);
}

static SplineFont *SearchBitmapResources(AFILE *f,long rlistpos,int subcnt,
					 long rdata_pos, long name_list,
					 char *filename, FOND * fondlist,
					 int flags) {
   long start=aftell(f);
   long roff;
   int rname=-1;
   int ch1, ch2;
   int i, j;
   int res_id;
   char *name;
   FOND *fond;
   int style;
   SplineFont *sf;
   int find_id;
   SplineChar *sc;

   fond=PickFOND(fondlist, filename, &name, &style);
   if (fond==NULL)
      return (NULL);

   find_id=-1;
   if (flags&ttf_onlyonestrike) {
      int biggest=0;

      for (i=0; i<fond->assoc_cnt; ++i) {
	 if (fond->assoc[i].style==style && fond->assoc[i].size>biggest) {
	    biggest=fond->assoc[i].size;
	    find_id=fond->assoc[i].id;
	 }
      }
   }

   sf=SplineFontBlank(257);
   free(sf->fontname);
   sf->fontname=name;
   free(sf->familyname);
   sf->familyname=fastrdup(fond->fondname);
   sf->fondname=fastrdup(fond->fondname);
   free(sf->fullname);
   sf->fullname=fastrdup(name);
   free(sf->origname);
   sf->origname=NULL;
   if (style&sf_bold) {
      free(sf->weight);
      sf->weight=fastrdup("Bold");
   }
   free(sf->copyright);
   sf->copyright=NULL;
   free(sf->comments);
   sf->comments=NULL;

   sf->map=EncMapNew(257, 257, FindOrMakeEncoding("mac"));

   for (i=0; i<fond->stylewidthcnt; ++i) {
      if (fond->stylewidths[i].style==style) {
	 short *widths=fond->stylewidths[i].widthtab;

	 for (j=fond->first; j <= fond->last; ++j) {
	    sc=SFMakeChar(sf, sf->map, j);
	    sc->width=((widths[j-fond->first]*1000L+(1 << 11)) >> 12);
	    sc->widthset=true;
	 }
	 sc=SFSplineCharCreate(sf);
	 sc->orig_pos=sf->glyphcnt;
	 sf->glyphs[sf->glyphcnt++]=sc;
	 sc->name=fastrdup(".notdef");
	 sc->width =
	    (widths[fond->last+1-fond->first]*1000L+(1 << 11)) >> 12;
	 sc->widthset=true;
      }
   }

   afseek(f, rlistpos, SEEK_SET);
   for (i=0; i<subcnt; ++i) {
      res_id=aget_uint16_be(f);
      rname=(short) aget_uint16_be(f);
      /* flags=*/ agetc(f);
      ch1=agetc(f);
      ch2=agetc(f);
      roff=rdata_pos+((ch1 << 16)|(ch2 << 8)|agetc(f));
      /* mbz=*/ aget_int32_be(f);
      for (j=fond->assoc_cnt-1; j >= 0; --j)
	 if ((find_id != -1 && res_id==find_id) ||
	     (fond->assoc[j].style==style && fond->assoc[j].id==res_id &&
	      fond->assoc[j].size != 0))
	    LoadNFNT(f, roff, sf, fond->assoc[j].size);
   }
   afseek(f, start, SEEK_SET);

   sf->onlybitmaps=true;
   SFOrderBitmapList(sf);
   return (sf);
}

/* Look for kerning info and merge it into the currently existing font "into" */
static SplineFont *FindFamilyStyleKerns(SplineFont *into,EncMap *map,
					FOND * fondlist, char *filename) {
   char *name;
   int style;
   FOND *fond;
   int i, j;
   int ch1, ch2, offset;
   KernPair *kp;
   SplineChar *sc1, *sc2;

   fond=PickFOND(fondlist, filename, &name, &style);
   if (fond==NULL || into==NULL)
      return (NULL);
   for (i=0; i<fond->stylekerncnt; ++i)
      if (fond->stylekerns[i].style==style)
	 break;
   if (i==fond->stylekerncnt) {
      ErrorMsg(2,"No kerning table for %s\n", name);
      free(name);
      return (NULL);
   }
   for (j=0; j<fond->stylekerns[i].kernpairs; ++j) {
      ch1=fond->stylekerns[i].kerns[j].ch1;
      ch2=fond->stylekerns[i].kerns[j].ch2;
      offset =
	 (fond->stylekerns[i].kerns[j].offset *
	  (into->ascent+into->descent)+(1 << 11)) >> 12;
      sc1=SFMakeChar(into, map, ch1);
      sc2=SFMakeChar(into, map, ch2);
      for (kp=sc1->kerns; kp != NULL; kp=kp->next)
	 if (kp->sc==sc2)
	    break;
      if (kp==NULL) {
	 uint32_t script;

	 kp=chunkalloc(sizeof(KernPair));
	 kp->sc=sc2;
	 kp->next=sc1->kerns;
	 sc1->kerns=kp;
	 script=SCScriptFromUnicode(sc1);
	 if (script==DEFAULT_SCRIPT)
	    script=SCScriptFromUnicode(sc2);
	 kp->subtable =
	    SFSubTableFindOrMake(sc1->parent, CHR('k', 'e', 'r', 'n'), script,
				 gpos_pair);
      }
      kp->off=offset;
   }
   return (into);
}

/* Look for a bare truetype font in a binhex/macbinary wrapper */
static SplineFont *MightBeTrueType(AFILE *binary,int32_t pos,int32_t dlen,
				   int flags, enum openflags openflags) {
   AFILE *temp=atmpfile();
   char *buffer=malloc(8192);
   int len;
   SplineFont *sf;

   if (flags&ttf_onlynames) {
      char **ret;
      char *temp=TTFGetFontName(binary, pos, pos);

      if (temp==NULL)
	 return (NULL);
      ret=malloc(2*sizeof(char *));
      ret[0]=temp;
      ret[1]=NULL;
      return ((SplineFont *) ret);
   }

   afseek(binary, pos, SEEK_SET);
   while (dlen>0) {
      len=dlen>8192?8192:dlen;
      len=afread(buffer, 1, dlen>8192?8192:dlen, binary);
      if (len==0)
	 break;
      afwrite(buffer, 1, len, temp);
      dlen -= len;
   }
   afseek(temp,0,SEEK_SET);
   sf=_SFReadTTF(temp, flags, openflags, NULL, NULL);
   afclose(temp);
   free(buffer);
   return (sf);
}

static SplineFont *IsResourceFork(AFILE *f,long offset,char *filename,
				  int flags, enum openflags openflags,
				  SplineFont *into, EncMap * map) {
   /* If it is a good resource fork then the first 16 bytes are repeated */
   /*  at the location specified in bytes 4-7 */
   /* We include an offset because if we are looking at a mac binary file */
   /*  the resource fork will actually start somewhere in the middle of the */
   /*  file, not at the beginning */
   unsigned char buffer[16], buffer2[16];
   long rdata_pos, map_pos, type_list, name_list, rpos;
   int32_t rdata_len, map_len;
   uint32_t nfnt_pos, font_pos, fond_pos;
   unsigned long tag;
   int i, cnt, subcnt, nfnt_subcnt=0, font_subcnt=0, fond_subcnt=0;
   SplineFont *sf;
   FOND *fondlist=NULL;

   afseek(f, offset, SEEK_SET);
   if (afread(buffer, 1, 16, f) != 16)
      return (NULL);
   rdata_pos =
      offset +
      ((buffer[0] << 24)|(buffer[1] << 16)|(buffer[2] << 8)|buffer[3]);
   map_pos =
      offset +
      ((buffer[4] << 24)|(buffer[5] << 16)|(buffer[6] << 8)|buffer[7]);
   rdata_len =
      ((buffer[8] << 24)|(buffer[9] << 16)|(buffer[10] << 8) |
       buffer[11]);
   map_len =
      ((buffer[12] << 24)|(buffer[13] << 16)|(buffer[14] << 8) |
       buffer[15]);
   if (rdata_pos+rdata_len != map_pos || rdata_len==0)
      return (NULL);
   afseek(f, map_pos, SEEK_SET);
   buffer2[15]=buffer[15]+1;	/* make it be different */
   if (afread(buffer2, 1, 16, f) != 16)
      return (NULL);

/* Apple's data fork resources appear to have a bunch of zeroes here instead */
/*  of a copy of the first 16 bytes */
   for (i=0; i<16; ++i)
      if (buffer2[i] != 0)
	 break;
   if (i != 16) {
      for (i=0; i<16; ++i)
	 if (buffer[i] != buffer2[i])
	    return (NULL);
   }
   aget_int32_be(f);			/* skip the handle to the next resource map */
   aget_uint16_be(f);		/* skip the file resource number */
   aget_uint16_be(f);		/* skip the attributes */
   type_list=map_pos+aget_uint16_be(f);
   name_list=map_pos+aget_uint16_be(f);

   afseek(f, type_list, SEEK_SET);
   cnt=aget_uint16_be(f)+1;
   for (i=0; i<cnt; ++i) {
      tag=aget_int32_be(f);
      /* printf("%c%c%c%c\n", tag>>24, (tag>>16)&0xff, (tag>>8)&0xff, tag&0xff ); */
      subcnt=aget_uint16_be(f)+1;
      rpos=type_list+aget_uint16_be(f);
      sf=NULL;
      if (tag==CHR('P', 'O', 'S', 'T') && !(flags&(ttf_onlystrikes|ttf_onlykerns)))	/* No FOND */
	 sf =
	    SearchPostScriptResources(f, rpos, subcnt, rdata_pos, name_list,
				      flags);
      else if (tag==CHR('s', 'f', 'n', 't') && !(flags&ttf_onlykerns))
	 sf =
	    SearchTtfResources(f, rpos, subcnt, rdata_pos, name_list,
			       filename, flags, openflags);
      else if (tag==CHR('N', 'F', 'N', 'T')) {
	 nfnt_pos=rpos;
	 nfnt_subcnt=subcnt;
      } else if (tag==CHR('F', 'O', 'N', 'T')) {
	 font_pos=rpos;
	 font_subcnt=subcnt;
      } else if (tag==CHR('F', 'O', 'N', 'D')) {
	 fond_pos=rpos;
	 fond_subcnt=subcnt;
      }
      if (sf != NULL)
	 return (sf);
   }
   if (flags&ttf_onlynames)	/* Not interested in bitmap resources here */
      return (NULL);

   if (flags&ttf_onlykerns) {	/* For kerns */
      if (fond_subcnt != 0)
	 fondlist =
	    BuildFondList(f, fond_pos, fond_subcnt, rdata_pos, name_list,
			  flags);
      into=FindFamilyStyleKerns(into, map, fondlist, filename);
      FondListFree(fondlist);
      return (into);
   }
   /* Ok. If no outline font, try for a bitmap */
   if (nfnt_subcnt==0) {
      nfnt_pos=font_pos;
      nfnt_subcnt=font_subcnt;
   }
   if (nfnt_subcnt != 0) {
      if (fond_subcnt != 0)
	 fondlist =
	    BuildFondList(f, fond_pos, fond_subcnt, rdata_pos, name_list,
			  flags);
      sf =
	 SearchBitmapResources(f, nfnt_pos, nfnt_subcnt, rdata_pos, name_list,
			       filename, fondlist, flags);
      FondListFree(fondlist);
      if (sf != NULL)
	 return (sf);
   }
   return ((SplineFont *)-1);	/* It's a valid resource file, but just has no fonts */
}


static SplineFont *IsResourceInBinary(AFILE *f,char *filename,int flags,
				      enum openflags openflags,
				      SplineFont *into, EncMap * map) {
   unsigned char header[128];
   unsigned long offset, dlen, rlen;

   if (afread(header, 1, 128, f) != 128)
      return (NULL);
   if (header[0] != 0 || header[74] != 0 || header[82] != 0 || header[1] <= 0
       || header[1]>33 || header[63] != 0 || header[2+header[1]] != 0)
      return (NULL);
   dlen =
      ((header[0x53] << 24)|(header[0x54] << 16)|(header[0x55] << 8) |
       header[0x56]);
   rlen =
      ((header[0x57] << 24)|(header[0x58] << 16)|(header[0x59] << 8) |
       header[0x5a]);
   /* 128 bytes for header, then the dlen is padded to a 128 byte boundary */
   offset=128+((dlen+127)&~127);
/* Look for a bare truetype font in a binhex/macbinary wrapper */
   if (dlen != 0 && rlen <= dlen) {
      int pos=aftell(f);

      afread(header, 1, 4, f);
      header[5]='\0';
      if (strcmp((char *) header, "OTTO")==0
	  || strcmp((char *) header, "true")==0
	  || strcmp((char *) header, "ttcf")==0 || (header[0]==0
						      && header[1]==1
						      && header[2]==0
						      && header[3]==0))
	 return (MightBeTrueType(f, pos, dlen, flags, openflags));
   }
   return (IsResourceFork(f, offset, filename, flags, openflags, into, map));
}

static int lastch=0,repeat=0;
static void outchr(AFILE *binary,int ch) {
   int i;

   if (repeat) {
      if (ch==0) {
	 /* no repeat, output a literal 0x90 (the repeat flag) */
	 lastch=0x90;
	 aputc(lastch, binary);
      } else {
	 for (i=1; i<ch; ++i)
	    aputc(lastch, binary);
      }
      repeat=0;
   } else if (ch==0x90) {
      repeat=1;
   } else {
      aputc(ch, binary);
      lastch=ch;
   }
}

static SplineFont *IsResourceInHex(AFILE *f,char *filename,int flags,
				   enum openflags openflags,
				   SplineFont *into, EncMap * map) {
   /* convert file from 6bit to 8bit */
   /* interesting data is enclosed between two colons */
   AFILE *binary=atmpfile();
   char *sixbit =
      "!\"#$%&'()*+,-012345689@ABCDEFGHIJKLMNPQRSTUVXYZ[`abcdefhijklmpqr";
   int ch, val, cnt, i, dlen, rlen;
   unsigned char header[20];
   char *pt;
   SplineFont *ret;

   if (binary==NULL) {
      ErrorMsg(2,"can't create temporary file\n");
      return (NULL);
   }

   lastch=repeat=0;
   while ((ch=agetc(f)) != ':');	/* There may be comments before file start */
   cnt=val=0;
   while ((ch=agetc(f)) != ':') {
      if (isspace(ch))
	 continue;
      for (pt=sixbit; *pt != ch && *pt != '\0'; ++pt);
      if (*pt=='\0') {
	 afclose(binary);
	 return (NULL);
      }
      val=(val << 6)|(pt-sixbit);
      if (++cnt==4) {
	 outchr(binary, (val >> 16)&0xff);
	 outchr(binary, (val >> 8)&0xff);
	 outchr(binary, val&0xff);
	 val=cnt=0;
      }
   }
   if (cnt != 0) {
      if (cnt==1)
	 outchr(binary, val << 2);
      else if (cnt==2) {
	 val <<= 4;
	 outchr(binary, (val >> 8)&0xff);
	 outchr(binary, val&0xff);
      } else if (cnt==3) {
	 val <<= 6;
	 outchr(binary, (val >> 16)&0xff);
	 outchr(binary, (val >> 8)&0xff);
	 outchr(binary, val&0xff);
      }
   }

   afseek(binary,0,SEEK_SET);
   ch=agetc(binary);		/* Name length */
   /* skip name */
   for (i=0; i<ch; ++i)
      agetc(binary);
   if (agetc(binary) != '\0') {
      afclose(binary);
      return (NULL);
   }
   afread(header, 1, 20, binary);
   dlen =
      (header[10] << 24)|(header[11] << 16)|(header[12] << 8) |
      header[13];
   rlen =
      (header[14] << 24)|(header[15] << 16)|(header[16] << 8) |
      header[17];
/* Look for a bare truetype font in a binhex/macbinary wrapper */
   if (dlen != 0 && rlen<dlen) {
      int pos=aftell(binary);

      afread(header, 1, 4, binary);
      header[5]='\0';
      if (strcmp((char *) header, "OTTO")==0
	  || strcmp((char *) header, "true")==0
	  || strcmp((char *) header, "ttcf")==0 || (header[0]==0
						      && header[1]==1
						      && header[2]==0
						      && header[3]==0)) {
	 ret=MightBeTrueType(binary, pos, dlen, flags, openflags);
	 afclose(binary);
	 return (ret);
      }
   }
   if (rlen==0) {
      afclose(binary);
      return (NULL);
   }

   ret =
      IsResourceFork(binary, aftell(binary)+dlen+2, filename, flags,
		     openflags, into, map);

   afclose(binary);
   return (ret);
}

static SplineFont *IsResourceInFile(char *filename,int flags,
				    enum openflags openflags,
				    SplineFont *into, EncMap * map) {
   AFILE *f;
   char *spt, *pt;
   SplineFont *sf;
   char *temp=filename, *lparen;

   if ((pt=strrchr(filename, '/'))==NULL)
      pt=filename;
   if ((lparen=strchr(pt, '(')) != NULL && strchr(lparen, ')') != NULL) {
      temp=fastrdup(filename);
      temp[lparen-filename]='\0';
   }
   f=afopen(temp, "rb");
   if (temp != filename)
      free(temp);
   if (f==NULL)
      return (NULL);
   spt=strrchr(filename, '/');
   if (spt==NULL)
      spt=filename;
   pt=strrchr(spt, '.');
   if (pt != NULL && (pt[1]=='b' || pt[1]=='B')
       && (pt[2]=='i' || pt[2]=='I') && (pt[3]=='n' || pt[3]=='N')
       && (pt[4]=='\0' || pt[4]=='(')) {
      if ((sf=IsResourceInBinary(f, filename, flags, openflags, into, map))) {
	 afclose(f);
	 return (sf);
      }
   } else if (pt != NULL && (pt[1]=='h' || pt[1]=='H')
	      && (pt[2]=='q' || pt[2]=='Q') && (pt[3]=='x'
						    || pt[3]=='X')
	      && (pt[4]=='\0' || pt[4]=='(')) {
      if ((sf=IsResourceInHex(f, filename, flags, openflags, into, map))) {
	 afclose(f);
	 return (sf);
      }
   }

   sf=IsResourceFork(f, 0, filename, flags, openflags, into, map);
   afclose(f);
   return (sf);
}

static SplineFont *FindResourceFile(char *filename,int flags,
				    enum openflags openflags,
				    SplineFont *into, EncMap * map) {
   char *spt, *pt, *dpt;
   char buffer[1400];
   SplineFont *sf;

   if ((sf=IsResourceInFile(filename, flags, openflags, into, map)))
      return (sf);

   /* Well, look in the resource fork directory (if it exists), the resource */
   /*  fork is placed there in a separate file on (some) non-Mac disks */
   strcpy(buffer, filename);
   spt=strrchr(buffer, '/');
   if (spt==NULL) {
      spt=buffer;
      pt=filename;
   } else {
      ++spt;
      pt=filename+(spt-buffer);
   }
   strcpy(spt, "resource.frk/");
   strcat(spt, pt);
   if ((sf=IsResourceInFile(buffer, flags, openflags, into, map)))
      return (sf);

   /* however the resource fork does not appear to do long names properly */
   /*  names are always lower case 8.3, do some simple things to check */
   spt=strrchr(buffer, '/')+1;
   for (pt=spt; *pt; ++pt)
      if (isupper(*pt))
	 *pt=tolower(*pt);
   dpt=strchr(spt, '.');
   if (dpt==NULL)
      dpt=spt+strlen(spt);
   if (dpt-spt>8 || strlen(dpt)>4) {
      char exten[8];

      strncpy(exten, dpt, 7);
      exten[4]='\0';		/* it includes the dot */
      if (dpt-spt>6)
	 dpt=spt+6;
      *dpt++='~';
      *dpt++='1';
      strcpy(dpt, exten);
   }
   return (IsResourceInFile(buffer, flags, openflags, into, map));
}

SplineFont *SFReadMacBinary(char *filename, int flags,
			    enum openflags openflags) {
   SplineFont *sf=FindResourceFile(filename, flags, openflags, NULL, NULL);

   if (sf==NULL)
      ErrorMsg(2,"Couldn't find a font file named %s\n", filename);
   else if (sf==(SplineFont *) (-1)) {
      ErrorMsg(2,"%s is a mac resource file but contains no postscript or truetype fonts\n",
	       filename);
      sf=NULL;
   }
   return (sf);
}

int LoadKerningDataFromMacFOND(SplineFont *sf, char *filename, EncMap * map) {
   if (FindResourceFile(filename, ttf_onlykerns, 0, sf, map)==NULL)
      return (false);

   return (true);
}

char **NamesReadMacBinary(char *filename) {
   return ((char **)
	   FindResourceFile(filename, ttf_onlynames, 0, NULL, NULL));
}
