/* $Id: parsettf.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 "fontanvil.h"
#include <chardata.h>
#include <utype.h>
#include <ustring.h>
#include <math.h>
#include "ttf.h"

#include "nonmactab.h"

char *SaveTablesPref;

int ask_user_for_cmap=false;

/* True Type is a really icky format. Nothing is together. It's badly described */
/*  much of the description is misleading */
/* Apple's version: */
/*  http://fonts.apple.com/TTRefMan/index.html */
/* MS's version: */
/*  http://www.microsoft.com/typography/tt/tt.htm */
/* An helpful but incomplete description is given at */
/*  http://www.truetype.demon.co.uk/ttoutln.htm */
/* For some things I looked at freetype's code to see how they did it */
/*  (I think only for what happens if !ARGS_ARE_XY) */
/*  http://freetype.sourceforge.net/ */
/* It grows on you though... now that I understand it better it seems better designed */
/*  but the docs remain in conflict. Sometimes badly so */

int prefer_cjk_encodings=false;

/* ************************************************************************** */
static struct ms_2_locales {
   char *loc_name;
   int local_id;
} ms_2_locals[]={
   {
   "af", 0x436}, {
   "sq_AL", 0x41c}, {
   "am", 0x45e}, {
   "ar_SA", 0x401}, {
   "ar_IQ", 0x801}, {
   "ar_EG", 0xc01}, {
   "ar_LY", 0x1001}, {
   "ar_DZ", 0x1401}, {
   "ar_MA", 0x1801}, {
   "ar_TN", 0x1C01}, {
   "ar_OM", 0x2001}, {
   "ar_YE", 0x2401}, {
   "ar_SY", 0x2801}, {
   "ar_JO", 0x2c01}, {
   "ar_LB", 0x3001}, {
   "ar_KW", 0x3401}, {
   "ar_AE", 0x3801}, {
   "ar_BH", 0x3c01}, {
   "ar_QA", 0x4001}, {
   "hy", 0x42b}, {
   "as", 0x44d}, {
   "az", 0x42c}, {
   "az", 0x82c}, {
   "eu", 0x42d}, {
   "be_BY", 0x423}, {
   "bn_IN", 0x445}, {
   "bn_BD", 0x845}, {
   "bg_BG", 0x402}, {
   "my", 0x455}, {
   "ca", 0x403}, {
   "km", 0x453}, {
   "zh_TW", 0x404},		/* Trad */
   {
   "zh_CN", 0x804},		/* Simp */
   {
   "zh_HK", 0xc04},		/* Trad */
   {
   "zh_SG", 0x1004},		/* Simp */
   {
   "zh_MO", 0x1404},		/* Trad */
   {
   "hr", 0x41a}, {
   "hr_BA", 0x101a}, {
   "cs_CZ", 0x405}, {
   "da_DK", 0x406}, {
   "div", 0x465}, {
   "nl_NL", 0x413}, {
   "nl_BE", 0x813}, {
   "en_UK", 0x809}, {
   "en_US", 0x409}, {
   "en_CA", 0x1009}, {
   "en_AU", 0xc09}, {
   "en_NZ", 0x1409}, {
   "en_IE", 0x1809}, {
   "en_ZA", 0x1c09}, {
   "en_JM", 0x2009}, {
   "en", 0x2409}, {
   "en_BZ", 0x2809}, {
   "en_TT", 0x2c09}, {
   "en_ZW", 0x3009}, {
   "en_PH", 0x3409}, {
   "en_ID", 0x3809}, {
   "en_HK", 0x3c09}, {
   "en_IN", 0x4009}, {
   "en_MY", 0x4409}, {
   "et_EE", 0x425}, {
   "fo", 0x438},
/* No language code for filipino */
   {
   "fa", 0x429}, {
   "fi_FI", 0x40b}, {
   "fr_FR", 0x40c}, {
   "fr_BE", 0x80c}, {
   "fr_CA", 0xc0c}, {
   "fr_CH", 0x100c}, {
   "fr_LU", 0x140c}, {
   "fr_MC", 0x180c}, {
   "fr", 0x1c0c},		/* West Indes */
   {
   "fr_RE", 0x200c}, {
   "fr_CD", 0x240c}, {
   "fr_SN", 0x280c}, {
   "fr_CM", 0x2c0c}, {
   "fr_CI", 0x300c}, {
   "fr_ML", 0x340c}, {
   "fr_MA", 0x380c}, {
   "fr_HT", 0x3c0c}, {
   "fr_DZ", 0xe40c},		/* North African is most likely to be Algeria, possibly Tunisia */
   {
   "fy", 0x462}, {
   "gl", 0x456}, {
   "ka", 0x437}, {
   "de_DE", 0x407}, {
   "de_CH", 0x807}, {
   "de_AT", 0xc07}, {
   "de_LU", 0x1007}, {
   "de_LI", 0x1407}, {
   "el_GR", 0x408}, {
   "ga", 0x83c}, {
   "gd", 0x43c}, {
   "gn", 0x474}, {
   "gu", 0x447}, {
   "ha", 0x468}, {
   "he_IL", 0x40d}, {
   "iw", 0x40d},		/* Obsolete name for Hebrew */
   {
   "hi", 0x439}, {
   "hu_HU", 0x40e}, {
   "is_IS", 0x40f}, {
   "id", 0x421}, {
   "in", 0x421},		/* Obsolete name for Indonesean */
   {
   "iu", 0x45d}, {
   "it_IT", 0x410}, {
   "it_CH", 0x810}, {
   "ja_JP", 0x411}, {
   "kn", 0x44b}, {
   "ks_IN", 0x860}, {
   "kk", 0x43f}, {
   "ky", 0x440}, {
   "km", 0x453}, {
   "kok", 0x457}, {
   "ko", 0x412}, {
   "ko", 0x812},		/*Johab */
   {
   "lo", 0x454}, {
   "la", 0x476}, {
   "lv_LV", 0x426}, {
   "lt_LT", 0x427}, {
   "lt", 0x827},		/* Classic */
   {
   "mk", 0x42f}, {
   "ms", 0x43e}, {
   "ms", 0x83e}, {
   "ml", 0x44c}, {
   "mt", 0x43a}, {
   "mr", 0x44e}, {
   "mn", 0x450}, {
   "ne_NP", 0x461}, {
   "ne_IN", 0x861}, {
   "no_NO", 0x414},		/* Bokmal */
   {
   "no_NO", 0x814},		/* Nynorsk */
   {
   "or", 0x448}, {
   "om", 0x472}, {
   "ps", 0x463}, {
   "pl_PL", 0x415}, {
   "pt_PT", 0x416}, {
   "pt_BR", 0x816}, {
   "pa_IN", 0x446}, {
   "pa_PK", 0x846}, {
   "qu_BO", 0x46b}, {
   "qu_EC", 0x86b}, {
   "qu_PE", 0xc6b}, {
   "rm", 0x417}, {
   "ro_RO", 0x418}, {
   "ro_MD", 0x818}, {
   "ru_RU", 0x419}, {
   "ru_MD", 0x819}, {
   "smi", 0x43b}, {
   "sa", 0x43b},
/* No language code for Sepedi */
   {
   "sr", 0xc1a},		/* Cyrillic */
   {
   "sr", 0x81a},		/* Latin */
   {
   "sd_IN", 0x459}, {
   "sd_PK", 0x859}, {
   "si", 0x45b}, {
   "sk_SK", 0x41b}, {
   "sl_SI", 0x424}, {
   "wen", 0x42e}, {
   "es_ES", 0x40a},		/* traditional spanish */
   {
   "es_MX", 0x80a}, {
   "es_ES", 0xc0a},		/* Modern spanish */
   {
   "es_GT", 0x100a}, {
   "es_CR", 0x140a}, {
   "es_PA", 0x180a}, {
   "es_DO", 0x1c0a}, {
   "es_VE", 0x200a}, {
   "es_CO", 0x240a}, {
   "es_PE", 0x280a}, {
   "es_AR", 0x2c0a}, {
   "es_EC", 0x300a}, {
   "es_CL", 0x340a}, {
   "es_UY", 0x380a}, {
   "es_PY", 0x3c0a}, {
   "es_BO", 0x400a}, {
   "es_SV", 0x440a}, {
   "es_HN", 0x480a}, {
   "es_NI", 0x4c0a}, {
   "es_PR", 0x500a}, {
   "es_US", 0x540a}, {
   "sutu", 0x430}, {
   "sw_KE", 0x441}, {
   "sv_SE", 0x41d}, {
   "sv_FI", 0x81d}, {
   "tl", 0x464}, {
   "tg", 0x464}, {
   "ta", 0x449}, {
   "tt", 0x444}, {
   "te", 0x44a}, {
   "th", 0x41e}, {
   "bo_CN", 0x451}, {
   "bo_BT", 0x451}, {
   "ti_ET", 0x473}, {
   "ti_ER", 0x873}, {
   "ts", 0x431}, {
   "tn", 0x432}, {
   "tr_TR", 0x41f}, {
   "tk", 0x442}, {
   "uk_UA", 0x422}, {
   "ug", 0x480}, {
   "ur_PK", 0x420}, {
   "ur_IN", 0x820}, {
   "uz", 0x443},		/* Latin */
   {
   "uz", 0x843},		/* Cyrillic */
   {
   "ven", 0x433}, {
   "vi", 0x42a}, {
   "cy", 0x452}, {
   "xh", 0x434}, {
   "yi", 0x43d}, {
   "ji", 0x43d},		/* Obsolete Yiddish */
   {
   "yo", 0x46a}, {
   "zu", 0x435}, {
   NULL, 0}
};

int MSLanguageFromLocale(void) {
   const char *lang=NULL;
   int i, langlen;
   static char *envs[]={ "LC_ALL","LC_MESSAGES","LANG",NULL };
   char langcountry[8], language[4];
   int langcode, langlocalecode;

   for (i=0; envs[i] != NULL; ++i) {
      lang=getenv(envs[i]);
      if (lang != NULL) {
	 langlen=strlen(lang);
	 if ((langlen>5 && lang[5]=='.' && lang[2]=='_') ||
	     (langlen==5 && lang[2]=='_') ||
	     (langlen==2) || (langlen==3))
	    /* Some obscure languages have a 3 letter code */
	    /* I understand this language */
	    break;
      }
   }
   if (lang==NULL)
      lang="en_US";
   strncpy(langcountry, lang, 5);
   langcountry[5]='\0';
   strncpy(language, lang, 3);
   language[3]='\0';
   if (language[2]=='_')
      language[2]='\0';
   langlen=strlen(language);

   langcode=langlocalecode=-1;
   for (i=0; ms_2_locals[i].loc_name != NULL; ++i) {
      if (strmatch(langcountry, ms_2_locals[i].loc_name)==0) {
	 langlocalecode=ms_2_locals[i].local_id;
	 langcode=langlocalecode&0x3ff;
	 break;
      } else if (strncmp(language, ms_2_locals[i].loc_name, langlen)==0)
	 langcode=ms_2_locals[i].local_id&0x3ff;
   }
   if (langcode==-1)		/* Default to English */
      langcode=0x9;
   return (langlocalecode==-1?(langcode|0x400):langlocalecode);
}

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

static int32_t getoffset(AFILE *ttf,int offsize) {
   if (offsize==1)
      return (agetc(ttf));
   else if (offsize==2)
      return (aget_uint16_be(ttf));
   else if (offsize==3)
      return (aget_uint24_be(ttf));
   else
      return (aget_int32_be(ttf));
}

static double get2dot14(AFILE *ttf) {
   int32_t val=aget_uint16_be(ttf);
   int mant=val&0x3fff;

   /* This oddity may be needed to deal with the first 2 bits being signed */
   /*  and the low-order bits unsigned */
   return ((double) ((val << 16) >> (16+14))+(mant/16384.0));
}

static Encoding *enc_from_platspec(int platform,int specific) {
   char *enc;
   Encoding *e;

   enc="Custom";
   if (platform==0) {
      enc="Unicode";
      if (specific==4)
	 enc="UnicodeFull";
   } else if (platform==1) {
      if (specific==0)
	 enc="Mac";
      else if (specific==1)
	 enc="Sjis";
      else if (specific==2)
	 enc="Big5hkscs";	/* Or should we just guess big5? Both are wrong sometimes */
      else if (specific==3)
	 enc="EUC-KR";
      else if (specific==25)
	 enc="EUC-CN";
   } else if (platform==2) {	/* obselete */
      if (specific==0)
	 enc="ASCII";
      else if (specific==1)
	 enc="Unicode";
      else if (specific==2)
	 enc="ISO8859-1";
   } else if (platform==3) {
      if (specific==1 || specific==0)	/* symbol (sp=0) is just unicode (PUA) */
	 enc="Unicode";
      else if (specific==2)
	 enc="Sjis";
      else if (specific==3)
	 enc="EUC-CN";
      else if (specific==4)
	 enc="Big5hkscs";
      else if (specific==5)
	 enc="EUC-KR";
      else if (specific==6)
	 enc="Johab";
      else if (specific==10)
	 enc="UnicodeFull";
   } else if (platform==7) {	/* Used internally in freetype, but */
      if (specific==0) {	/*  there's no harm in looking for it */
	 enc="AdobeStandard";	/*  even if it never happens */
      } else if (specific==1) {
	 /* adobe_expert */
	 ;
      } else if (specific==2) {
	 /* adobe_custom */
	 ;
      }
   }
   e=FindOrMakeEncoding(enc);
   if (e==NULL) {
      static int p=-1,s=-1;

      if (p != platform || s != specific) {
	 ErrorMsg(2,"The truetype encoding specified by platform=%d specific=%d (which we map to %s) is not supported by your version of iconv(3).\n",
		  platform, specific, enc);
	 p=platform;
	 s=specific;
      }
   }
   return (e);
}

static char *_readencstring(AFILE *ttf,int offset,int len,
			    int platform, int specific, int language) {
   long pos=aftell(ttf);
   unichar_t *str, *pt;
   char *ret;
   int i, ch;
   Encoding *enc;

   afseek(ttf, offset, SEEK_SET);

   if (platform==1) {
      /* Mac is screwy, there are several different varients of MacRoman */
      /*  depending on the language, they didn't get it right when they  */
      /*  invented their script system */
      char *cstr, *cpt;

      cstr=cpt=malloc(len+1);
      for (i=0; i<len; ++i)
	 *cpt++=agetc(ttf);
      *cpt='\0';
      ret=MacStrToUtf8(cstr, specific, language);
      free(cstr);
   } else {
      enc=enc_from_platspec(platform, specific);
      if (enc==NULL)
	 return (NULL);
      if (enc->is_unicodebmp) {
	 str=pt=malloc((sizeof(unichar_t)/2)*len+sizeof(unichar_t));
	 for (i=0; i<len/2; ++i) {
	    ch=agetc(ttf) << 8;
	    *pt++=ch|agetc(ttf);
	 }
	 *pt=0;
      } else if (enc->unicode != NULL) {
	 str=pt=malloc(sizeof(unichar_t)*len+sizeof(unichar_t));
	 for (i=0; i<len; ++i)
	    *pt++=enc->unicode[agetc(ttf)];
	 *pt=0;
      } else if (enc->tounicode != NULL) {
	 size_t inlen=len+1, outlen=sizeof(unichar_t)*(len+1);
	 char *cstr=malloc(inlen), *cpt;
	 ICONV_CONST char *in=cstr;
	 char *out;

	 for (cpt=cstr, i=0; i<len; ++i)
	    *cpt++=agetc(ttf);
	 str=malloc(outlen+sizeof(unichar_t));
	 out=(char *) str;
	 iconv(enc->tounicode, &in, &inlen, &out, &outlen);
	 out[0]='\0';
	 out[1]='\0';
	 out[2]='\0';
	 out[3]='\0';
	 free(cstr);
      } else {
	 str=uc_copy("");
      }
      ret=u2utf8_copy(str);
      free(str);
   }
   afseek(ttf, pos, SEEK_SET);
   return (ret);
}

char *TTFGetFontName(AFILE *ttf, int32_t offset, int32_t off2) {
   int i, num;
   int32_t tag, nameoffset, length, stringoffset;
   int plat, spec, lang, name, len, off, val;
   int fullval, fullstr, fulllen, famval, famstr, famlen;
   Encoding *enc;
   int fullplat, fullspec, fulllang, famplat, famspec, famlang;
   int locale=MSLanguageFromLocale();
   int maclang=WinLangToMac(locale);

   afseek(ttf, offset, SEEK_SET);
   /* version=*/ aget_int32_be(ttf);
   num=aget_uint16_be(ttf);
   /* srange=*/ aget_uint16_be(ttf);
   /* esel=*/ aget_uint16_be(ttf);
   /* rshift=*/ aget_uint16_be(ttf);
   for (i=0; i<num; ++i) {
      tag=aget_int32_be(ttf);
      /* checksum=*/ aget_int32_be(ttf);
      nameoffset=off2+aget_int32_be(ttf);
      length=aget_int32_be(ttf);
      if (tag==CHR('n', 'a', 'm', 'e'))
	 break;
   }
   if (i==num)
      return (NULL);

   afseek(ttf, nameoffset, SEEK_SET);
   /* format=*/ aget_uint16_be(ttf);
   num=aget_uint16_be(ttf);
   stringoffset=nameoffset+aget_uint16_be(ttf);
   fullval=famval=0;
   for (i=0; i<num; ++i) {
      plat=aget_uint16_be(ttf);
      spec=aget_uint16_be(ttf);
      lang=aget_uint16_be(ttf);
      name=aget_uint16_be(ttf);
      len=aget_uint16_be(ttf);
      off=aget_uint16_be(ttf);
      enc=enc_from_platspec(plat, spec);
      if (enc==NULL)
	 continue;
      val=0;
      if (plat==3 && !enc->is_custom && lang==locale)
	 val=15;
      else if (plat==3 && !enc->is_custom
	       && (lang&0xff)==(locale&0xff))
	 val=14;
      else if ((plat==0 || plat==1) && !enc->is_custom && lang==maclang)
	 val=13;
      /* Ok, that didn't work, how about an english name? */
      else if (plat==3 && !enc->is_custom && lang==0x409)
	 val=12;
      else if (plat==3 && !enc->is_custom && (lang&0xff)==0x09)
	 val=11;
      else if ((plat==0 || plat==1) && !enc->is_custom && lang==0)
	 val=10;
      /* failing that I'll take what I can get */
      else if (!enc->is_custom)
	 val=1;
      if (name==4 && val>fullval) {
	 fullval=val;
	 fullstr=off;
	 fulllen=len;
	 fullplat=plat;
	 fullspec=spec;
	 fulllang=lang;
	 if (val==12)
	    break;
      } else if (name==1 && val>famval) {
	 famval=val;
	 famstr=off;
	 famlen=len;
	 famplat=plat;
	 famspec=spec;
	 famlang=lang;
      }
   }
   if (fullval==0) {
      if (famval==0)
	 return (NULL);
      fullstr=famstr;
      fulllen=famlen;
      fullplat=famplat;
      fullspec=famspec;
      fulllang=famlang;
   }
   return (_readencstring
	   (ttf, stringoffset+fullstr, fulllen, fullplat, fullspec,
	    fulllang));
}

static int PickTTFFont(AFILE *ttf,char *filename,char **chosenname) {
   int32_t *offsets, cnt, i, choice, j;
   char **names;
   char *pt, *lparen, *rparen;

   /* TTCF version=*/ aget_int32_be(ttf);
   cnt=aget_int32_be(ttf);
   if (cnt==1) {
      /* This is easy, don't bother to ask the user, there's no choice */
      int32_t offset=aget_int32_be(ttf);

      afseek(ttf, offset, SEEK_SET);
      return (true);
   }
   offsets=malloc(cnt * sizeof(int32_t));
   for (i=0; i<cnt; ++i)
      offsets[i]=aget_int32_be(ttf);
   names=malloc(cnt * sizeof(char *));
   for (i=j=0; i<cnt; ++i) {
      names[j]=TTFGetFontName(ttf, offsets[i], 0);
      if (names[j] != NULL)
	 ++j;
   }
   pt=strrchr(filename, '/');
   if (pt==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 (choice=cnt-1; choice >= 0; --choice)
	 if (strcmp(names[choice], find)==0)
	    break;
      if (choice==-1) {
	 char *end;

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

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

   if (choice != -1) {
      afseek(ttf, offsets[choice], SEEK_SET);
      *chosenname=fastrdup(names[choice]);
   }
   for (i=0; i<j; ++i)
      free(names[i]);
   free(names);
   free(offsets);
   return (choice != -1);
}

static int PickCFFFont(char **fontnames) {
   unichar_t **names;
   int cnt, i, choice;

   for (cnt=0; fontnames[cnt] != NULL; ++cnt);
   names=calloc(cnt+1, sizeof(unichar_t *));
   for (i=0; i<cnt; ++i)
      names[i]=uc_copy(fontnames[i]);
   choice=0;

   for (i=0; i<cnt; ++i)
      free(names[i]);
   free(names);
   return (choice);
}

static void ParseSaveTablesPref(struct ttfinfo *info) {
   extern char *SaveTablesPref;
   char *pt, *spt;
   int cnt;

   info->savecnt=0;
   info->savetab=NULL;
   if (SaveTablesPref==NULL || *SaveTablesPref=='\0')
      return;
   for (pt=SaveTablesPref, cnt=0; *pt; ++pt)
      if (*pt==',')
	 ++cnt;
   info->savecnt=cnt+1;
   info->savetab=calloc(cnt+1, sizeof(struct savetab));
   for (pt=spt=SaveTablesPref, cnt=0;; ++pt) {
      if (*pt==',' || *pt=='\0') {
	 uint32_t tag;

	 tag=((spt<pt)?spt[0]:' ') << 24;
	 tag |= ((spt+1<pt)?spt[1]:' ') << 16;
	 tag |= ((spt+2<pt)?spt[2]:' ') << 8;
	 tag |= ((spt+3<pt)?spt[3]:' ');
	 info->savetab[cnt++].tag=tag;
	 if (*pt)
	    spt=pt+1;
	 else
	    break;
      }
   }
}

static int32_t regionchecksom(AFILE *file,int start,int len) {
   uint32_t sum=0, chunk;

   afseek(file, start, SEEK_SET);
   if (len != -1)
      len=(len+3) >> 2;
   while (len==-1 || --len >= 0) {
      chunk=aget_int32_be(file);
      if (afeof(file))
	 break;
      sum += chunk;
   }
   return (sum);
}

static void ValidateTTFHead(AFILE *ttf,struct ttfinfo *info) {
   /* When doing fontlint we want to check the ttf header and make */
   /* sure all the offsets and lengths are valid, and the checksums */
   /* match. Most of the time this is just extra work and we don't */
   /* bother */
   uint32_t restore_this_pos=aftell(ttf);
   struct tt_tables {
      uint32_t tag;
      uint32_t checksum;
      uint32_t offset;
      uint32_t length;
   } *tabs, temp;
   int i, j;
   uint32_t file_len;
   int sr, es, rs, e_sr, e_es, e_rs;
   int hashead, hashhea, hasmaxp, masos2, haspost, hasname, hasos2;
   int hasloca, hascff, hasglyf;

   info->numtables=aget_uint16_be(ttf);
   sr=aget_uint16_be(ttf);
   es=aget_uint16_be(ttf);
   rs=aget_uint16_be(ttf);
   e_sr =
      (info->numtables<8?4:info->numtables<16?8:info->numtables <
       32?16:info->numtables<64?32:64)*16;
   e_es =
      (info->numtables<8?2:info->numtables<16?3:info->numtables <
       32?4:info->numtables<64?5:6);
   e_rs=info->numtables*16-e_sr;
   if (e_sr != sr || e_es != es || e_rs != rs) {
      ErrorMsg(2,"Unexpected values for binsearch header. Based on the number of tables I\n expect searchRange=%d (not %d), entrySel=%d (not %d) rangeShift=%d (not %d)\n",
	       e_sr, sr, e_es, es, e_rs, rs);
      info->bad_sfnt_header=true;
   }

   if (info->numtables <= 0) {
      ErrorMsg(2,"An sfnt file must contain SOME tables, but this one does not.\n");
      info->bad_sfnt_header=true;
      afseek(ttf, restore_this_pos, SEEK_SET);
      return;
   } else if (info->numtables>1000) {
      ErrorMsg(2,"An sfnt file may contain a large number of tables, but this one has over 1000\n and that seems like too many\n");
      info->bad_sfnt_header=true;
      afseek(ttf, restore_this_pos, SEEK_SET);
      return;
   }

   tabs=malloc(info->numtables * sizeof(struct tt_tables));

   for (i=0; i<info->numtables; ++i) {
      tabs[i].tag=aget_int32_be(ttf);
      tabs[i].checksum=aget_int32_be(ttf);
      tabs[i].offset=aget_int32_be(ttf);
      tabs[i].length=aget_int32_be(ttf);
      if (i != 0 && tabs[i].tag<tabs[i-1].tag && !info->bad_sfnt_header) {
	 ErrorMsg(2,"Table tags should be in alphabetic order in the font header\n but '%c%c%c%c', appears after '%c%c%c%c'.\n",
		  tabs[i-1].tag >> 24, tabs[i-1].tag >> 16,
		  tabs[i-1].tag >> 8, tabs[i-1].tag, tabs[i].tag >> 24,
		  tabs[i].tag >> 16, tabs[i].tag >> 8, tabs[i].tag);
	 info->bad_sfnt_header=true;
      }
   }
   afseek(ttf, 0, SEEK_END);
   file_len=aftell(ttf);

   for (i=0; i<info->numtables; ++i)
      for (j=i+1; j<info->numtables; ++j) {
	 if (tabs[i].offset>tabs[j].offset) {
	    temp=tabs[i];
	    tabs[i]=tabs[j];
	    tabs[j]=temp;
	 }
      }
   for (i=0; i<info->numtables-1; ++i) {
      for (j=i+1; j<info->numtables; ++j) {
	 if (tabs[i].tag==tabs[j].tag) {
	    ErrorMsg(2,"Same table tag, '%c%c%c%c', appears twice in sfnt header\n",
		     tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
		     tabs[i].tag);
	    info->bad_sfnt_header=true;
	 }
      }
      if (tabs[i].offset+tabs[i].length>tabs[i+1].offset) {
	 ErrorMsg(2,"Tables '%c%c%c%c' and '%c%c%c%c' overlap\n",
		  tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
		  tabs[i].tag, tabs[j].tag >> 24, tabs[j].tag >> 16,
		  tabs[j].tag >> 8, tabs[j].tag);
      }
   }
   if (tabs[i].offset+tabs[i].length>file_len) {
      ErrorMsg(2,"Table '%c%c%c%c' extends beyond end of file.\n",
	       tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
	       tabs[i].tag);
      info->bad_sfnt_header=true;
   }

   /* Checksums. First file as a whole, then each table */
   if (regionchecksom(ttf, 0, -1) != 0xb1b0afba) {
      ErrorMsg(2,"File checksum is incorrect.\n");
      info->bad_sfnt_header=true;
   }
   for (i=0; i<info->numtables-1; ++i)
      if (tabs[i].tag != CHR('h', 'e', 'a', 'd')) {
	 if (regionchecksom(ttf, tabs[i].offset, tabs[i].length) !=
	     tabs[i].checksum) {
	    ErrorMsg(2,"Table '%c%c%c%c' has a bad checksum.\n",
		     tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
		     tabs[i].tag);
	    info->bad_sfnt_header=true;
	 }
      }

   hashead=hashhea=hasmaxp=masos2=haspost=hasname=hasos2=false;
   hasloca=hascff=hasglyf=false;
   for (i=0; i<info->numtables-1; ++i) {
      switch (tabs[i].tag) {
	case CHR('c', 'v', 't', ' '):
	   if (tabs[i].length&1)
	      ErrorMsg(2,"Table '%c%c%c%c' has a bad length, must be even.\n",
		       tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
		       tabs[i].tag);
	   break;
	case CHR('b', 'h', 'e', 'd'):	/* Fonts with bitmaps but no outlines get bhea */
	case CHR('h', 'e', 'a', 'd'):
	   if (tabs[i].length != 54)
	      ErrorMsg(2,"Table '%c%c%c%c' has a bad length, must be 54 but is %d.\n",
		       tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
		       tabs[i].tag, tabs[i].length);
	   hashead=true;
	   break;
	case CHR('h', 'h', 'e', 'a'):
	   hashhea=true;
	case CHR('v', 'h', 'e', 'a'):
	   if (tabs[i].length != 36)
	      ErrorMsg(2,"Table '%c%c%c%c' has a bad length, must be 36 but is %d.\n",
		       tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
		       tabs[i].tag, tabs[i].length);
	   break;
	case CHR('m', 'a', 'x', 'p'):
	   hasmaxp=true;
	   if (tabs[i].length != 32 && tabs[i].length != 6)
	      ErrorMsg(2,"Table '%c%c%c%c' has a bad length, must be 32 or 6 but is %d.\n",
		       tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
		       tabs[i].tag, tabs[i].length);
	   break;
	case CHR('O', 'S', '/', '2'):
	   hasos2=true;
	   if (tabs[i].length != 78 && tabs[i].length != 86
	       && tabs[i].length != 96)
	      ErrorMsg(2,"Table '%c%c%c%c' has a bad length, must be 78, 86 or 96 but is %d.\n",
		       tabs[i].tag >> 24, tabs[i].tag >> 16, tabs[i].tag >> 8,
		       tabs[i].tag, tabs[i].length);
	   break;
	case CHR('p', 'o', 's', 't'):
	   haspost=true;
	   break;
	case CHR('n', 'a', 'm', 'e'):
	   hasname=true;
	   break;
	case CHR('l', 'o', 'c', 'a'):
	   hasloca=true;
	   break;
	case CHR('g', 'l', 'y', 'f'):
	   hasglyf=true;
	   break;
	case CHR('C', 'F', 'F', ' '):
	   hascff=true;
	   break;
      }
   }
   if (!hashead)
      ErrorMsg(2,"Missing required table: \"head\"\n");
   if (!hashhea)
      ErrorMsg(2,"Missing required table: \"hhea\"\n");
   if (!hasmaxp)
      ErrorMsg(2,"Missing required table: \"maxp\"\n");
   if (!haspost)
      ErrorMsg(2,"Missing required table: \"post\"\n");
   if (!hasname)
      ErrorMsg(2,"Missing required table: \"name\"\n");
   if (hasglyf && !hasloca)
      ErrorMsg(2,"Missing required table: \"loca\"\n");
   if (!hasos2)
      ErrorMsg(2,"Missing \"OS/2\" table\n");
   if (!hasglyf && hasloca)
      ErrorMsg(2,"Missing required table: \"glyf\"\n");
   if (!hasglyf && !hascff)
      ErrorMsg(2,"This font contains neither \"CFF \" nor \"glyf\"/\"loca\" tables\n");

   free(tabs);
   afseek(ttf, restore_this_pos, SEEK_SET);
}

static struct tablenames {
   uint32_t tag;
   char *name;
} stdtables[]={
   {
   CHR('a', 'c', 'n', 't'), "accent attachment table"}, {
   CHR('a', 'v', 'a', 'r'), "axis variation table"}, {
   CHR('B', 'A', 'S', 'E'), "Baseline table (OT version)"}, {
   CHR('b', 'd', 'a', 't'), "bitmap data table (AAT version)"}, {
   CHR('B', 'D', 'F', ' '), "BDF bitmap properties table"}, {
   CHR('b', 'h', 'e', 'd'), "bitmap font header table"}, {
   CHR('b', 'l', 'o', 'c'), "bitmap location table (AAT version)"}, {
   CHR('b', 's', 'l', 'n'), "baseline table (AAT version)"}, {
   CHR('C', 'F', 'F', ' '),
	 "PostScript font program (Compact Font Format)"}, {
   CHR('C', 'I', 'D', ' '), "Obsolete table for a type1 CID keyed font"}, {
   CHR('c', 'm', 'a', 'p'), "character code mapping table"}, {
   CHR('c', 'v', 'a', 'r'), "CVT variation table"}, {
   CHR('c', 'v', 't', ' '), "control value table"}, {
   CHR('D', 'S', 'I', 'G'), "digital signature table"}, {
   CHR('E', 'B', 'D', 'T'), "bitmap data table (OT version)"}, {
   CHR('E', 'B', 'L', 'C'), "bitmap location table (OT version)"}, {
   CHR('E', 'B', 'S', 'C'), "embedded bitmap scaling control table"}, {
   CHR('E', 'L', 'U', 'A'), "electronic end user license table"}, {
   CHR('f', 'd', 's', 'c'), "font descriptor table"}, {
   CHR('f', 'e', 'a', 't'), "layout feature table"}, {
   CHR('F', 'e', 'a', 't'), "SIL Graphite layout feature table"}, {
   CHR('F', 'F', 'T', 'M'), "FontAnvil time stamp table"}, {
   CHR('f', 'm', 't', 'x'), "font metrics table"}, {
   CHR('f', 'p', 'g', 'm'), "font program table"}, {
   CHR('f', 'v', 'a', 'r'), "font variation table"}, {
   CHR('g', 'a', 's', 'p'),
	 "grid-fitting and scan-conversion procedure table"}, {
   CHR('G', 'D', 'E', 'F'), "glyph definition table"}, {
   CHR('G', 'l', 'a', 't'), "Graphite glyph attribute table"}, {
   CHR('G', 'l', 'o', 'c'), "Graphite glyph location in Glat table"}, {
   CHR('g', 'l', 'y', 'f'), "glyph outline table"}, {
   CHR('G', 'P', 'O', 'S'), "glyph positioning table"}, {
   CHR('g', 'v', 'a', 'r'), "glyph variation table"}, {
   CHR('G', 'S', 'U', 'B'), "glyph substitution table"}, {
   CHR('h', 'd', 'm', 'x'), "horizontal device metrics table"}, {
   CHR('h', 'e', 'a', 'd'), "font header table"}, {
   CHR('h', 'h', 'e', 'a'), "horizontal header table"}, {
   CHR('h', 'm', 't', 'x'), "horizontal metrics table"}, {
   CHR('h', 's', 't', 'y'), "horizontal style table"}, {
   CHR('j', 'u', 's', 't'), "justification table (AAT version)"}, {
   CHR('J', 'S', 'T', 'F'), "justification table (OT version)"}, {
   CHR('k', 'e', 'r', 'n'), "kerning table"}, {
   CHR('l', 'c', 'a', 'r'), "ligature caret table"}, {
   CHR('l', 'o', 'c', 'a'), "glyph location table"}, {
   CHR('L', 'T', 'S', 'H'), "linear threshold table"}, {
   CHR('M', 'A', 'T', 'H'), "math table"}, {
   CHR('m', 'a', 'x', 'p'), "maximum profile table"}, {
   CHR('M', 'M', 'S', 'D'), "Multi-Master table, obsolete"}, {
   CHR('M', 'M', 'F', 'X'), "Multi-Master table, obsolete"}, {
   CHR('m', 'o', 'r', 't'), "metamorphosis table"}, {
   CHR('m', 'o', 'r', 'x'), "extended metamorphosis table"}, {
   CHR('n', 'a', 'm', 'e'), "name table"}, {
   CHR('o', 'p', 'b', 'd'), "optical bounds table"}, {
   CHR('O', 'S', '/', '2'), "OS/2 and Windows specific metrics table"}, {
   CHR('P', 'C', 'L', 'T'), "PCL 5 data table"}, {
   CHR('P', 'f', 'E', 'd'), "FontAnvil font debugging table"}, {
   CHR('p', 'o', 's', 't'),
	 "glyph name and PostScript compatibility table"}, {
   CHR('p', 'r', 'e', 'p'), "control value program table"}, {
   CHR('p', 'r', 'o', 'p'), "properties table"}, {
   CHR('S', 'i', 'l', 'f'), "SIL Graphite rule table"}, {
   CHR('S', 'i', 'l', 'l'), "(unspecified) SIL Graphite table"}, {
   CHR('S', 'i', 'l', 't'), "unknown SIL table"}, {
   CHR('T', 'e', 'X', ' '), "TeX table"}, {
   CHR('t', 'r', 'a', 'k'), "tracking table"}, {
   CHR('T', 'Y', 'P', '1'), "Obsolete table for a type1 font"}, {
   CHR('V', 'D', 'M', 'X'), "vertical device metrics table"}, {
   CHR('v', 'h', 'e', 'a'), "vertical header table"}, {
   CHR('v', 'm', 't', 'x'), "vertical metrics table"}, {
   CHR('V', 'O', 'R', 'G'), "vertical origin table"}, {
   CHR('Z', 'a', 'p', 'f'), "glyph reference table"}, {
   0, NULL}
};

static int readttfheader(AFILE *ttf,struct ttfinfo *info,char *filename,
			 char **choosenname) {
   int i, j, k;
   int tag, checksum, offset, length, version;
   int first=true;

   version=aget_int32_be(ttf);
   if (version==CHR('t', 't', 'c', 'f')) {
      /* TrueType font collection */
      info->is_ttc=true;
      if (!PickTTFFont(ttf, filename, choosenname))
	 return (0);
      /* If they picked a font, then we should be left pointing at the */
      /*  start of the Table Directory for that font */
      info->one_of_many=true;
      version=aget_int32_be(ttf);
   }

   /* Apple says that 'typ1' is a valid code for a type1 font wrapped up in */
   /*  a truetype table structure, but gives no docs on what tables get used */
   /*  or how */ /* Turns out to be pretty simple */
   /* typ1 is used for both type1 fonts and CID type1 fonts, I don't think a version of 'CID ' is actually used */
   if (version==CHR('t', 'y', 'p', '1')
       || version==CHR('C', 'I', 'D', ' ')) {
      ErrorMsg(2,"Nifty, you've got one of the old Apple/Adobe type1 sfnts here\n");
   } else if (version != 0x00010000 && version != CHR('t', 'r', 'u', 'e') && version != 0x00020000 &&	/* Windows 3.1 Chinese version used this version for some arphic fonts */
	      /* See discussion on freetype list, july 2004 */
	      version != CHR('O', 'T', 'T', 'O'))
      return (0);		/* Not version 1 of true type, nor Open Type */

   if (info->openflags&of_fontlint)
      ValidateTTFHead(ttf, info);

   info->numtables=aget_uint16_be(ttf);
   /* searchRange=*/ aget_uint16_be(ttf);
   /* entrySelector=*/ aget_uint16_be(ttf);
   /* rangeshift=*/ aget_uint16_be(ttf);

   ParseSaveTablesPref(info);

   for (i=0; i<info->numtables; ++i) {
      tag=aget_int32_be(ttf);
      checksum=aget_int32_be(ttf);
      offset=aget_int32_be(ttf);
      length=aget_int32_be(ttf);
#ifdef DEBUG
      printf("%c%c%c%c\n", tag >> 24, (tag >> 16)&0xff, (tag >> 8)&0xff,
	     tag&0xff);
#endif
      switch (tag) {
	case CHR('B', 'A', 'S', 'E'):
	   info->base_start=offset;
	   break;
	case CHR('b', 's', 'l', 'n'):
	   info->bsln_start=offset;
	   break;
	case CHR('C', 'F', 'F', ' '):
	   info->cff_start=offset;
	   info->cff_length=length;
	   break;
	case CHR('c', 'm', 'a', 'p'):
	   info->encoding_start=offset;
	   break;
	case CHR('g', 'a', 's', 'p'):
	   info->gasp_start=offset;
	   break;
	case CHR('g', 'l', 'y', 'f'):
	   info->glyph_start=offset;
	   info->glyph_length=length;
	   break;
	case CHR('G', 'D', 'E', 'F'):
	   info->gdef_start=offset;
	   info->gdef_length=length;
	   break;
	case CHR('G', 'P', 'O', 'S'):
	   info->gpos_start=offset;
	   info->gpos_length=length;
	   break;
	case CHR('G', 'S', 'U', 'B'):
	   info->gsub_start=offset;
	   info->gsub_length=length;
	   break;
	case CHR('b', 'd', 'a', 't'):	/* Apple/MS use a different tag, but the same format. Great. */
	case CHR('E', 'B', 'D', 'T'):
	   info->bitmapdata_start=offset;
	   info->bitmapdata_length=length;
	   break;
	case CHR('b', 'l', 'o', 'c'):	/* Apple/MS use a different tag. Great. */
	case CHR('E', 'B', 'L', 'C'):
	   info->bitmaploc_start=offset;
	   info->bitmaploc_length=length;
	   break;
	case CHR('b', 'h', 'e', 'd'):	/* Apple uses bhed for fonts with only bitmaps */
	case CHR('h', 'e', 'a', 'd'):
	   info->head_start=offset;
	   break;
	case CHR('h', 'h', 'e', 'a'):
	   info->hhea_start=offset;
	   break;
	case CHR('h', 'm', 't', 'x'):
	   info->hmetrics_start=offset;
	   break;
	case CHR('J', 'S', 'T', 'F'):
	   info->jstf_start=offset;
	   info->jstf_length=length;
	   break;
	case CHR('k', 'e', 'r', 'n'):
	   info->kern_start=offset;
	   break;
	case CHR('l', 'o', 'c', 'a'):
	   info->glyphlocations_start=offset;
	   info->loca_length=length;
	   info->glyph_cnt=length/2-1;	/* the minus one is because there is one extra entry to give the length of the last glyph */
	   if (info->glyph_cnt<0)
	      info->glyph_cnt=0;
	   break;
	case CHR('m', 'a', 'x', 'p'):
	   info->maxp_start=offset;
	   info->maxp_len=length;
	   break;
	case CHR('n', 'a', 'm', 'e'):
	   info->copyright_start=offset;
	   break;
	case CHR('p', 'o', 's', 't'):
	   info->postscript_start=offset;
	   break;
	case CHR('O', 'S', '/', '2'):
	   info->os2_start=offset;
	   break;
	case CHR('C', 'I', 'D', ' '):
	case CHR('T', 'Y', 'P', '1'):
	   info->typ1_start=offset;
	   info->typ1_length=length;
	   break;
	case CHR('v', 'h', 'e', 'a'):
	   info->vhea_start=offset;
	   break;
	case CHR('v', 'm', 't', 'x'):
	   info->vmetrics_start=offset;
	   break;
	case CHR('M', 'A', 'T', 'H'):
	   info->math_start=offset;
	   info->math_length=length;
	   break;
	   /* Apple stuff */
	case CHR('f', 'e', 'a', 't'):
	   info->feat_start=offset;
	   break;
	case CHR('l', 'c', 'a', 'r'):
	   info->lcar_start=offset;
	   break;
	case CHR('m', 'o', 'r', 't'):
	   info->mort_start=offset;
	   break;
	case CHR('m', 'o', 'r', 'x'):
	   info->morx_start=offset;
	   break;
	case CHR('o', 'p', 'b', 'd'):
	   info->opbd_start=offset;
	   break;
	case CHR('p', 'r', 'o', 'p'):
	   info->prop_start=offset;
	   break;
	   /* to make sense of instrs */
	case CHR('c', 'v', 't', ' '):
	   info->cvt_start=offset;
	   info->cvt_len=length;
	   break;
	case CHR('p', 'r', 'e', 'p'):
	   info->prep_start=offset;
	   info->prep_len=length;
	   break;
	case CHR('f', 'p', 'g', 'm'):
	   info->fpgm_start=offset;
	   info->fpgm_len=length;
	   break;

	   /* non-standard tables I've added */
	case CHR('P', 'f', 'E', 'd'):
	   info->pfed_start=offset;
	   break;
	case CHR('F', 'F', 'T', 'M'):
	   info->fftm_start=offset;
	   break;
	case CHR('T', 'e', 'X', ' '):
	   info->tex_start=offset;
	   break;
	case CHR('B', 'D', 'F', ' '):
	   info->bdf_start=offset;
	   break;

	   /* Apple's mm fonts */
	case CHR('g', 'v', 'a', 'r'):
	   info->gvar_start=offset;
	   info->gvar_len=length;
	   break;
	case CHR('f', 'v', 'a', 'r'):
	   info->fvar_start=offset;
	   info->fvar_len=length;
	   break;
	case CHR('a', 'v', 'a', 'r'):
	   info->avar_start=offset;
	   info->avar_len=length;
	   break;
	case CHR('c', 'v', 'a', 'r'):
	   info->cvar_start=offset;
	   info->cvar_len=length;
	   break;

	default:
	   for (j=0; j<info->savecnt; ++j)
	      if (info->savetab[j].tag==tag) {
		 info->savetab[j].offset=offset;
		 info->savetab[j].len=length;
		 break;
	      }
	   if (j==info->savecnt) {
	      if (first) {
		 ErrorMsg(2,"The following table(s) in the font have been ignored by FontAnvil\n");
		 first=false;
	      }
	      for (k=0; stdtables[k].tag != 0; ++k)
		 if (stdtables[k].tag==tag)
		    break;
	      if (stdtables[k].tag==0) {
		 ErrorMsg(2,"  Ignoring '%c%c%c%c'\n", tag >> 24, tag >> 16,
			  tag >> 8, tag);
	      } else {
		 ErrorMsg(2,"  Ignoring '%c%c%c%c' %s\n", tag >> 24,
			  tag >> 16, tag >> 8, tag, stdtables[k].name);
	      }
	   }
      }
   }
   if (info->glyphlocations_start != 0 && info->cff_start != 0)
      ErrorMsg(2,"This font contains both truetype and PostScript glyph descriptions\n  only one will be used.\n");
   else if ((info->glyphlocations_start != 0)+(info->cff_start != 0) +
	    (info->typ1_start != 0)>1)
      ErrorMsg(2,"This font contains multiple glyph descriptions\n  only one will be used.\n");
   if (info->gpos_start != 0 && info->kern_start != 0)
      ErrorMsg(2,"This font contains both a 'kern' table and a 'GPOS' table.\n  The 'kern' table will only be read if there is no 'kern' feature in 'GPOS'.\n");
   if ((info->mort_start != 0 || info->morx_start != 0)
       && info->gsub_start != 0)
      ErrorMsg(2,"This font contains both a 'mor[tx]' table and a 'GSUB' table.\n  FF will only read feature/settings in 'morx' which do not match features\n  found in 'GSUB'.\n");
   if (info->base_start != 0 && info->bsln_start != 0)
      ErrorMsg(2,"This font contains both a 'BASE' table and a 'bsln' table.\n  FontAnvil will only read one of them ('BASE').\n");
   return (true);
}

static void readdate(AFILE *ttf,struct ttfinfo *info,int ismod) {
   int date[4], date1970[4], year[2];
   int i;

   /* Dates in sfnt files are seconds since 1904. I adjust to unix time */
   /*  seconds since 1970 by figuring out how many seconds were in between */

   date[3]=aget_uint16_be(ttf);
   date[2]=aget_uint16_be(ttf);
   date[1]=aget_uint16_be(ttf);
   date[0]=aget_uint16_be(ttf);
   memset(date1970, 0, sizeof(date1970));
   year[0]=(60*60*24*365L)&0xffff;
   year[1]=(60*60*24*365L) >> 16;
   for (i=1904; i<1970; ++i) {
      date1970[0] += year[0];
      date1970[1] += year[1];
      if ((i&3)==0 && (i%100 != 0 || i%400==0))
	 date1970[0] += 24*60*60L;	/* Leap year */
      date1970[1] += (date1970[0] >> 16);
      date1970[0] &= 0xffff;
      date1970[2] += date1970[1] >> 16;
      date1970[1] &= 0xffff;
      date1970[3] += date1970[2] >> 16;
      date1970[2] &= 0xffff;
   }

   for (i=0; i<3; ++i) {
      date[i] -= date1970[i];
      date[i+1] += date[i] >> 16;
      date[i] &= 0xffff;
   }
   date[3] -= date1970[3];

   *(ismod?&info->modificationtime:&info->creationtime) =
      (((long long) date[3]) << 48) |
      (((long long) date[2]) << 32)|(date[1] << 16)|date[0];
}

static void readttfhead(AFILE *ttf,struct ttfinfo *info) {
   /* Here I want units per em, and size of loca entries */
   /* oh... also creation/modification times */
   int i, flags;

   afseek(ttf, info->head_start+4, SEEK_SET);	/* skip over the version number */
   info->sfntRevision=aget_int32_be(ttf);
   (void) aget_int32_be(ttf);
   (void) aget_int32_be(ttf);
   flags=aget_uint16_be(ttf);
   info->optimized_for_cleartype=(flags&(1 << 13))?1:0;
   info->apply_lsb=!(flags&(1 << 1));
   info->emsize=aget_uint16_be(ttf);

   info->ascent=.8*info->emsize;
   info->descent=info->emsize-info->ascent;

   for (i=0; i<8; ++i)
      aget_uint16_be(ttf);
   for (i=0; i<4; ++i)
      info->fbb[i]=(short) aget_uint16_be(ttf);
   info->macstyle=aget_uint16_be(ttf);
   for (i=0; i<2; ++i)
      aget_uint16_be(ttf);
   info->index_to_loc_is_long=aget_uint16_be(ttf);
   if (info->index_to_loc_is_long)
      info->glyph_cnt=info->loca_length/4-1;
   if (info->glyph_cnt<0)
      info->glyph_cnt=0;

   if (info->fftm_start != 0) {
      afseek(ttf, info->fftm_start+3*4, SEEK_SET);
   } else {
      afseek(ttf, info->head_start+4*4+2+2, SEEK_SET);
   }
   readdate(ttf, info, 0);
   readdate(ttf, info, 1);
}

static void readttfhhea(AFILE *ttf,struct ttfinfo *info) {
   /* Here I want ascent, descent and the number of horizontal metrics */
   int i;

   afseek(ttf, info->hhea_start+4, SEEK_SET);	/* skip over the version number */
   info->pfminfo.hhead_ascent=aget_uint16_be(ttf);
   info->pfminfo.hhead_descent=(short) aget_uint16_be(ttf);
   info->pfminfo.hheadascent_add=info->pfminfo.hheaddescent_add=false;
   info->pfminfo.linegap=(short) aget_uint16_be(ttf);
   info->advanceWidthMax=aget_uint16_be(ttf);
   info->pfminfo.hheadset=true;
   /*info->ascent=info->pfminfo.hhead_ascent; */

   for (i=0; i<11; ++i)
      aget_uint16_be(ttf);
   info->width_cnt=aget_uint16_be(ttf);
}

static void readttfmaxp(AFILE *ttf,struct ttfinfo *info) {
   /* All I want here is the number of glyphs */
   int cnt;

   afseek(ttf, info->maxp_start+4, SEEK_SET);	/* skip over the version number */
   cnt=aget_uint16_be(ttf);
   if (info->glyph_cnt==0 && info->glyph_length==0
       && info->loca_length <= 4 && info->cff_length==0
       && info->typ1_start==0) {
      /* X11 OpenType bitmap format */ ;
      info->onlystrikes=true;
   } else if (cnt != info->glyph_cnt && info->loca_length != 0) {
      ErrorMsg(2,"Font file has bad glyph count field.  maxp says: "
                 "%d sizeof(loca)=>%d\n",cnt,info->glyph_cnt);
      info->bad_glyph_data=true;
      if (cnt>info->glyph_cnt)
	 cnt=info->glyph_cnt;	/* Use the smaller of the two values */
   }
   /* Open Type fonts have no loca table, so we can't calculate the glyph */
   /*  count from it */
   info->glyph_cnt=cnt;
   if (cnt<0)
      info->glyph_cnt=0;
}

static char *stripspaces(char *str) {
   char *str2=str, *base=str;

   if (str==NULL)
      return (NULL);

   while (*str) {
      if (*str==' ')
	 ++str;
      else
	 *str2++=*str++;
   }
   *str2='\0';
   return (base);
}

static struct macname *AddMacName(AFILE *ttf,
				  int strlength, int stroff, int spec,
				  int language, struct macname *last) {
   struct macname *new=chunkalloc(sizeof(struct macname));
   long pos=aftell(ttf);
   char *pt;
   int i;

   new->next=last;
   new->enc=spec;
   new->lang=language;
   new->name=pt=malloc(strlength+1);

   afseek(ttf, stroff, SEEK_SET);

   for (i=0; i<strlength; ++i)
      *pt++=agetc(ttf);
   *pt='\0';

   afseek(ttf, pos, SEEK_SET);
   return (new);
}

static void MacFeatureAdd(AFILE *ttf,struct ttfinfo *info,int id,
			  int strlength, int stroff, int spec, int language) {
   MacFeat *f;
   struct macsetting *s;

   for (f=info->features; f != NULL; f=f->next) {
      if (f->strid==id) {
	 f->featname =
	    AddMacName(ttf, strlength, stroff, spec, language, f->featname);
	 return;
      } else {
	 for (s=f->settings; s != NULL; s=s->next) {
	    if (s->strid==id) {
	       s->setname =
		  AddMacName(ttf, strlength, stroff, spec, language,
			     s->setname);
	       return;
	    }
	 }
      }
   }
   /* Well, there are some things in the name table other than feature/setting */
   /*  names. Let's keep track of everything just in case.... */
   if (info->fvar_start != 0) {
      struct macidname *mi, *p;

      for (p=NULL, mi=info->macstrids; mi != NULL && mi->id != id;
	   p=mi, mi=mi->next);
      if (mi==NULL) {
	 mi=chunkalloc(sizeof(struct macidname));
	 mi->id=id;
	 mi->last=mi->head =
	    AddMacName(ttf, strlength, stroff, spec, language, NULL);
	 if (p==NULL)
	    info->macstrids=mi;
	 else
	    p->next=mi;
      } else {
	 mi->last->next =
	    AddMacName(ttf, strlength, stroff, spec, language, NULL);
	 mi->last=mi->last->next;
      }
   }
}

static void ValidatePostScriptFontName(struct ttfinfo *info,char *str) {
   char *end, *pt, *npt;
   int complained=false;

   /* someone gave me a font where the fontname started with the utf8 byte */
   /*  order mark.  PLRM says only ASCII encoding is supported. CFF says */
   /*  only printable ASCII should be used */
   if (((uint8_t *) str)[0]==0xef && ((uint8_t *) str)[1]==0xbb
       && ((uint8_t *) str)[2]==0xbf) {
      ErrorMsg(2,"The fontname begins with the utf8 byte order sequence. This is illegal. %s\n",
	       str+3);
      info->bad_ps_fontname=true;
      for (pt=str+3; *pt; ++pt)
	 pt[-3]=*pt;		/* ANSI says we can't strcpy overlapping strings */
   }
   strtod(str, &end);
   if ((*end=='\0' || (isdigit(str[0]) && strchr(str, '#') != NULL)) &&
       *str != '\0') {
      ErrorMsg(2,"A Postscript name may not be a number.\n");
      info->bad_ps_fontname=true;
      *str='a';
      complained=true;
   }
   for (pt=str; *pt; ++pt) {
      if (*pt <= ' ' || *pt >= 0x7f ||
	  *pt=='(' || *pt=='[' || *pt=='{' || *pt=='<' ||
	  *pt==')' || *pt==']' || *pt=='}' || *pt=='>' ||
	  *pt=='%' || *pt=='/') {
	 if (!complained) {
	    ErrorMsg(2,"The PostScript font name \"%.63s\" is invalid.\n"
	               "It should be printable ASCII,\nmust not contain "
	               "(){}[]<>%%/ or space,\nand it must be shorter than "
	               "63 characters.\n",str);
	    info->bad_ps_fontname=true;
	 }
	 complained=true;
	 for (npt=pt; npt[1]; ++npt)
	    *npt=npt[1];
	 *npt='\0';
	 --pt;
      }
   }
   if (strlen(str)>63) {
	    ErrorMsg(2,"The PostScript font name \"%.63s\" is invalid.\n"
	               "It should be printable ASCII,\nmust not contain "
	               "(){}[]<>%%/ or space,\nand it must be shorter than "
	               "63 characters.\n",str);
      info->bad_ps_fontname=true;
      str[63]='\0';
   }
}

char *EnforcePostScriptName(char *old) {
   char *end, *pt, *npt, *str=fastrdup(old);

   if (old==NULL)
      return (old);

   strtod(str, &end);
   if ((*end=='\0' || (isdigit(str[0]) && strchr(str, '#') != NULL)) &&
       *str != '\0') {
      free(str);
      str=malloc(strlen(old)+2);
      *str='a';
      strcpy(str+1, old);
   }
   for (pt=str; *pt; ++pt) {
      if (*pt <= ' ' || *pt >= 0x7f ||
	  *pt=='(' || *pt=='[' || *pt=='{' || *pt=='<' ||
	  *pt==')' || *pt==']' || *pt=='}' || *pt=='>' ||
	  *pt=='%' || *pt=='/') {
	 for (npt=pt; npt[1]; ++npt)
	    *npt=npt[1];
	 *npt='\0';
      }
   }
   if (strlen(str)>63)
      str[63]='\0';
   return (str);
}

static int IsSubSetOf(const char *substr,const char *fullstr) {
   /* The mac string is often a subset of the unicode string. Certain */
   /*  characters can't be expressed in the mac encoding and are omitted */
   /*  or turned to question marks or some such */
   const char *pt1, *pt2;
   uint32_t ch1, ch2;

   for (pt1=substr, pt2=fullstr, ch1=utf8_ildb(&pt1); ch1 != 0;) {
      if (*pt2=='\0')
	 break;
      ch2=utf8_ildb(&pt2);
      if (ch1==ch2)
	 ch1=utf8_ildb(&pt1);
   }
   if (ch1=='\0')
      return (true);

   for (pt1=substr, pt2=fullstr, ch1=utf8_ildb(&pt1); ch1 != 0;) {
      if (*pt2=='\0')
	 break;
      ch2=utf8_ildb(&pt2);
      if (ch1==ch2 || ch1=='?')
	 ch1=utf8_ildb(&pt1);
   }
   return (ch1=='\0');
}

static void TTFAddLangStr(AFILE *ttf,struct ttfinfo *info,int id,
			  int strlength, int stroff, int plat, int spec,
			  int language) {
   struct ttflangname *cur, *prev;
   char *str;

   if (plat==1 && id >= 256
       && (info->features != NULL || info->fvar_start != 0)) {
      MacFeatureAdd(ttf, info, id, strlength, stroff, spec, language);
      return;
   } else if (id<0 || id >= ttf_namemax)
      return;

   str=_readencstring(ttf, stroff, strlength, plat, spec, language);
   if (str==NULL)		/* we didn't understand the encoding */
      return;
   if (id==ttf_postscriptname)
      ValidatePostScriptFontName(info, str);
   if (*str=='\0') {
      free(str);
      return;
   }

   if (plat==1 || plat==0)
      language=WinLangFromMac(language);
   if ((language&0xff00)==0)
      language |= 0x400;

   for (prev=NULL, cur=info->names; cur != NULL && cur->lang != language;
	prev=cur, cur=cur->next);
   if (cur==NULL) {
      cur=chunkalloc(sizeof(struct ttflangname));
      cur->lang=language;
      if (prev==NULL)
	 info->names=cur;
      else
	 prev->next=cur;
   }
   if (cur->names[id]==NULL) {
      cur->names[id]=str;
      if (plat==1 || plat==0)
	 cur->frommac[id/32] |= (1 << (id&0x1f));
   } else if (strcmp(str, cur->names[id])==0) {
      free(str);
      if (plat==3)
	 cur->frommac[id/32] &= ~(1 << (id&0x1f));
   } else if (plat==1) {
      /* Mac string doesn't match mac unicode string */
      if (!IsSubSetOf(str, cur->names[id]))
	 ErrorMsg(2,"Warning: Mac and Unicode entries in the 'name' table differ for the\n %s string in the language %s\n Mac String: %s\nMac Unicode String: %s\n",
		  TTFNameIds(id), MSLangString(language), str,
		  cur->names[id]);
      else
	 ErrorMsg(2,"Warning: Mac string is a subset of the Unicode string in the 'name' table\n for the %s string in the %s language.\n",
		  TTFNameIds(id), MSLangString(language));
      free(str);
   } else if (plat==3 && (cur->frommac[id/32]&(1 << (id&0x1f)))) {
      if (!IsSubSetOf(cur->names[id], str))
	 ErrorMsg(2,"Warning: Mac and Windows entries in the 'name' table differ for the\n %s string in the language %s\n Mac String: %s\nWindows String: %s\n",
		  TTFNameIds(id), MSLangString(language), cur->names[id],
		  str);
      else
	 ErrorMsg(2,"Warning: Mac string is a subset of the Windows string in the 'name' table\n for the %s string in the %s language.\n",
		  TTFNameIds(id), MSLangString(language));
      free(cur->names[id]);
      cur->names[id]=str;
      cur->frommac[id/32] &= ~(1 << (id&0x1f));
   } else {
      int ret;
      extern int running_script;

      if (info->dupnamestate != 0)
	 ret=info->dupnamestate;
      else if (running_script)
	 ret=3;
      else {
	 ret =0;
      }
      if (ret==0 || ret==1)
	 free(str);
      else {
	 free(cur->names[id]);
	 cur->names[id]=str;
      }
   }
}

static int is_ascii(char *str) {	/* isascii is in ctype */
   if (str==NULL)
      return (false);
   while (*str && *str<127 && *str >= ' ')
      ++str;
   return (*str=='\0');
}

static char *FindLangEntry(struct ttfinfo *info,int id) {
   /* Look for an entry with string id */
   /* we prefer english, if we can't find english look for something in ascii */
   struct ttflangname *cur;
   char *ret;

   for (cur=info->names; cur != NULL && cur->lang != 0x409;
	cur=cur->next);
   if (cur != NULL && cur->names[id]==NULL)
      cur=NULL;
   if (cur==NULL)
      for (cur=info->names; cur != NULL && (cur->lang&0xf) != 0x09;
	   cur=cur->next);
   if (cur != NULL && cur->names[id]==NULL)
      cur=NULL;
   if (cur==NULL)
      for (cur=info->names; cur != NULL && !is_ascii(cur->names[id]);
	   cur=cur->next);
   if (cur==NULL)
      for (cur=info->names; cur != NULL && cur->names[id]==NULL;
	   cur=cur->next);
   if (cur==NULL)
      return (NULL);
   ret=fastrdup(cur->names[id]);
   return (ret);
}

struct otfname *FindAllLangEntries(AFILE *ttf, struct ttfinfo *info, int id) {
   /* Look for all entries with string id under windows platform */
   int32_t here=aftell(ttf);
   int i, cnt, tableoff;
   int platform, specific, language, name, str_len, stroff;
   struct otfname *head=NULL, *cur;

   if (info->copyright_start != 0 && id != 0) {
      afseek(ttf, info->copyright_start, SEEK_SET);
      /* format selector=*/ aget_uint16_be(ttf);
      cnt=aget_uint16_be(ttf);
      tableoff=info->copyright_start+aget_uint16_be(ttf);
      for (i=0; i<cnt; ++i) {
	 platform=aget_uint16_be(ttf);
	 specific=aget_uint16_be(ttf);
	 language=aget_uint16_be(ttf);
	 name=aget_uint16_be(ttf);
	 str_len=aget_uint16_be(ttf);
	 stroff=aget_uint16_be(ttf);

	 if (platform==3 && name==id) {
	    char *temp =
	       _readencstring(ttf, tableoff+stroff, str_len, platform,
			      specific, language);
	    if (temp != NULL) {
	       cur=chunkalloc(sizeof(struct otfname));
	       cur->next=head;
	       head=cur;
	       cur->lang=language;
	       cur->name=temp;
	    }
	 }
      }
      afseek(ttf, here, SEEK_SET);
   }
   return (head);
}

static struct macname *reversemacnames(struct macname *mn) {
   struct macname *next, *prev=NULL;

   if (mn==NULL)
      return (NULL);

   next=mn->next;
   while (next != NULL) {
      mn->next=prev;
      prev=mn;
      mn=next;
      next=mn->next;
   }
   mn->next=prev;
   return (mn);
}

static void readttfcopyrights(AFILE *ttf,struct ttfinfo *info) {
   int i, cnt, tableoff;
   int platform, specific, language, name, str_len, stroff;

   if (info->feat_start != 0)
      readmacfeaturemap(ttf, info);
   if (info->copyright_start != 0) {
      afseek(ttf, info->copyright_start, SEEK_SET);
      /* format selector=*/ aget_uint16_be(ttf);
      cnt=aget_uint16_be(ttf);
      tableoff=info->copyright_start+aget_uint16_be(ttf);
      for (i=0; i<cnt; ++i) {
	 platform=aget_uint16_be(ttf);
	 specific=aget_uint16_be(ttf);
	 language=aget_uint16_be(ttf);
	 name=aget_uint16_be(ttf);
	 str_len=aget_uint16_be(ttf);
	 stroff=aget_uint16_be(ttf);

	 TTFAddLangStr(ttf, info, name, str_len, tableoff+stroff,
		       platform, specific, language);
      }
   }

   if (info->copyright==NULL)
      info->copyright=FindLangEntry(info, ttf_copyright);
   if (info->familyname==NULL)
      info->familyname=FindLangEntry(info, ttf_family);
   if (info->fullname==NULL)
      info->fullname=FindLangEntry(info, ttf_fullname);
   if (info->version==NULL)
      info->version=FindLangEntry(info, ttf_version);
   if (info->fontname==NULL)
      info->fontname=FindLangEntry(info, ttf_postscriptname);

   if (info->fontname != NULL && *info->fontname=='\0') {
      free(info->fontname);
      info->fontname=NULL;
   }
   if (info->familyname != NULL && *info->familyname=='\0') {
      free(info->familyname);
      info->familyname=NULL;
   }
   if (info->fullname != NULL && *info->fullname=='\0') {
      free(info->fullname);
      info->fullname=NULL;
   }

   /* OpenType spec says the version string should begin with "Version " and */
   /*  end with a space and have a number in between */
   if (info->version==NULL)
      info->version=fastrdup("1.0");
   else if (strnmatch(info->version, "Version ", 8)==0) {
      char *temp=fastrdup(info->version+8);

      if (temp[strlen(temp)-1]==' ')
	 temp[strlen(temp)-1]='\0';
      free(info->version);
      info->version=temp;
   }
   if (info->fontname==NULL) {
      if (info->fullname != NULL)
	 info->fontname=stripspaces(fastrdup(info->fullname));
      if (info->fontname==NULL && info->familyname != NULL)
	 info->fontname=stripspaces(fastrdup(info->familyname));
      if (info->fontname != NULL)
	 ValidatePostScriptFontName(info, info->fontname);
   }

   if (info->features) {
      MacFeat *mf;
      struct macsetting *ms;

      for (mf=info->features; mf != NULL; mf=mf->next) {
	 mf->featname=reversemacnames(mf->featname);
	 for (ms=mf->settings; ms != NULL; ms=ms->next)
	    ms->setname=reversemacnames(ms->setname);
      }
   }
}

static void readttfpreglyph(AFILE *ttf,struct ttfinfo *info) {
   if (info->head_start != 0)
      readttfhead(ttf, info);
   if (info->hhea_start != 0)
      readttfhhea(ttf, info);
   if (info->maxp_start != 0)
      readttfmaxp(ttf, info);
   readttfcopyrights(ttf, info);	/* This one has internal checks */
}

#define _On_Curve	1
#define _X_Short	2
#define _Y_Short	4
#define _Repeat		8
#define _X_Same		0x10
#define _Y_Same		0x20

static void FigureControls(SplinePoint *from,SplinePoint *to,
			   BasePoint * cp, int is_order2) {
   /* What are the control points for 2 cp bezier which will provide the same */
   /*  curve as that for the 1 cp bezier specified above */
   double b, c, d;

   if (is_order2) {
      from->nextcp=to->prevcp=*cp;
   } else {
      d=from->me.x;
      c=2*cp->x-2*from->me.x;
      b=to->me.x+from->me.x-2*cp->x;
      from->nextcp.x=d+c/3;
      to->prevcp.x=from->nextcp.x+(c+b)/3;

      d=from->me.y;
      c=2*cp->y-2*from->me.y;
      b=to->me.y+from->me.y-2*cp->y;
      from->nextcp.y=d+c/3;
      to->prevcp.y=from->nextcp.y+(c+b)/3;
   }

   if (from->me.x != from->nextcp.x || from->me.y != from->nextcp.y
       || from->nextcpindex<0xfffe)
      from->nonextcp=false;
   if (to->me.x != to->prevcp.x || to->me.y != to->prevcp.y
       || from->nextcpindex<0xfffe)
      to->noprevcp=false;
   if (is_order2 && (to->noprevcp || from->nonextcp)) {
      to->noprevcp=from->nonextcp=true;
      from->nextcp=from->me;
      to->prevcp=to->me;
   }
}

static SplineSet *ttfbuildcontours(int path_cnt,uint16_t *endpt,char *flags,
				   BasePoint * pts, int is_order2) {
   SplineSet *head=NULL, *last=NULL, *cur;
   int i, path, start, last_off;
   SplinePoint *sp;

   for (path=i=0; path<path_cnt; ++path) {
      if (endpt[path]<i)	/* Sigh. Yes there are fonts with bad endpt info */
	 continue;
      cur=chunkalloc(sizeof(SplineSet));
      if (head==NULL)
	 head=cur;
      else
	 last->next=cur;
      last=cur;
      last_off=false;
      start=i;
      sp=NULL;
      while (i <= endpt[path]) {
	 if (flags[i]&_On_Curve) {
	    sp=chunkalloc(sizeof(SplinePoint));
	    sp->me=sp->nextcp=sp->prevcp=pts[i];
	    sp->nonextcp=sp->noprevcp=true;
	    sp->ttfindex=i;
	    sp->nextcpindex=0xffff;
	    if (last_off && cur->last != NULL)
	       FigureControls(cur->last, sp, &pts[i-1], is_order2);
	    last_off=false;
	 } else if (last_off) {
	    /* two off curve points get a third on curve point created */
	    /* half-way between them. Now isn't that special */
	    sp=chunkalloc(sizeof(SplinePoint));
	    sp->me.x=(pts[i].x+pts[i-1].x)/2;
	    sp->me.y=(pts[i].y+pts[i-1].y)/2;
	    sp->nextcp=sp->prevcp=sp->me;
	    sp->nonextcp=true;
	    sp->ttfindex=0xffff;
	    sp->nextcpindex=i;
	    if (last_off && cur->last != NULL)
	       FigureControls(cur->last, sp, &pts[i-1], is_order2);
	    /* last_off continues to be true */
	 } else {
	    if (cur->first != NULL)
	       cur->last->nextcpindex=i;
	    last_off=true;
	    sp=NULL;
	 }
	 if (sp != NULL) {
	    if (cur->first==NULL)
	       cur->first=sp;
	    else
	       SplineMake(cur->last, sp, is_order2);
	    cur->last=sp;
	 }
	 ++i;
      }
      if (start==i-1) {
	 /* MS chinese fonts have contours consisting of a single off curve */
	 /*  point. What on earth do they think that means? */
	 /* Oh. I see. It's used to possition marks and such */
	 if (cur->first==NULL) {
	    sp=chunkalloc(sizeof(SplinePoint));
	    sp->me.x=pts[start].x;
	    sp->me.y=pts[start].y;
	    sp->nextcp=sp->prevcp=sp->me;
	    sp->nonextcp=sp->noprevcp=true;
	    sp->ttfindex=i-1;
	    sp->nextcpindex=0xffff;
	    cur->first=cur->last=sp;
	 }
      } else if (!(flags[start]&_On_Curve) && !(flags[i-1]&_On_Curve)) {
	 sp=chunkalloc(sizeof(SplinePoint));
	 sp->me.x=(pts[start].x+pts[i-1].x)/2;
	 sp->me.y=(pts[start].y+pts[i-1].y)/2;
	 sp->nextcp=sp->prevcp=sp->me;
	 sp->nonextcp=true;
	 sp->ttfindex=0xffff;
	 sp->nextcpindex=start;
	 FigureControls(cur->last, sp, &pts[i-1], is_order2);
	 SplineMake(cur->last, sp, is_order2);
	 cur->last=sp;
	 FigureControls(sp, cur->first, &pts[start], is_order2);
      } else if (!(flags[i-1]&_On_Curve)) {
	 FigureControls(cur->last, cur->first, &pts[i-1], is_order2);
	 cur->last->nextcpindex=i-1;
      } else if (!(flags[start]&_On_Curve)) {
	 FigureControls(cur->last, cur->first, &pts[start], is_order2);
	 sp->nextcpindex=start;
      }
      if (cur->last != cur->first) {
	 SplineMake(cur->last, cur->first, is_order2);
	 cur->last=cur->first;
      }
      for (sp=cur->first;;) {
	 if (sp->ttfindex != 0xffff && SPInterpolate(sp))
	    sp->dontinterpolate=true;
	 if (sp->next==NULL)
	    break;
	 sp=sp->next->to;
	 if (sp==cur->first)
	    break;
      }
   }
   return (head);
}

static void readttfsimpleglyph(AFILE *ttf,struct ttfinfo *info,
			       SplineChar * sc, int path_cnt, int gbb[4]) {
   uint16_t *endpt=malloc((path_cnt+1)*sizeof(uint16_t));
   uint8_t *instructions;
   char *flags;
   BasePoint *pts;
   int i, j, tot, len;
   int last_pos;

   for (i=0; i<path_cnt; ++i) {
      endpt[i]=aget_uint16_be(ttf);
      if (i != 0 && endpt[i]<endpt[i-1]) {
	 info->bad_glyph_data=true;
	 ErrorMsg(2,"Bad tt font: contour ends make no sense in glyph %d.\n",
		  sc->orig_pos);
	 return;
      }
   }
   if (path_cnt==0) {
      tot=0;
      pts=malloc(sizeof(BasePoint));
   } else {
      tot=endpt[path_cnt-1]+1;
      pts=malloc(tot * sizeof(BasePoint));
   }

   len=aget_uint16_be(ttf);
   instructions=malloc(len);
   for (i=0; i<len; ++i)
      instructions[i]=agetc(ttf);

   flags=malloc(tot);
   for (i=0; i<tot; ++i) {
      flags[i]=agetc(ttf);
      if (flags[i]&_Repeat) {
	 int cnt=agetc(ttf);

	 if (i+cnt >= tot) {
	    ErrorMsg(2,"Flag count is wrong (or total is): %d %d\n", i+cnt, tot);
	    cnt=tot-i-1;
	 }
	 for (j=0; j<cnt; ++j)
	    flags[i+j+1]=flags[i];
	 i += cnt;
      }
      if (afeof(ttf))
	 break;
   }
   if (i != tot)
      ErrorMsg(2,"Flag count is wrong (or total is): %d %d in glyph %d\n", i, tot,
	     sc->orig_pos);

   last_pos=0;
   for (i=0; i<tot; ++i) {
      if (flags[i]&_X_Short) {
	 int off=agetc(ttf);

	 if (!(flags[i]&_X_Same))
	    off=-off;
	 pts[i].x=last_pos+off;
      } else if (flags[i]&_X_Same)
	 pts[i].x=last_pos;
      else
	 pts[i].x=last_pos+(short) aget_uint16_be(ttf);
      last_pos=pts[i].x;
      if ((last_pos<gbb[0] || last_pos>gbb[2]) && (flags[i]&_On_Curve)) {
	 if (!info->gbbcomplain || (info->openflags&of_fontlint)) {
	    ErrorMsg(2,"A point in GID %d is outside the glyph bounding box\n",
		     sc->orig_pos);
	    info->bad_glyph_data=true;
	    if (!(info->openflags&of_fontlint))
	       ErrorMsg(2,"  Subsequent errors will not be reported.\n");
	    info->gbbcomplain=true;
	 }
      }
   }

   last_pos=0;
   for (i=0; i<tot; ++i) {
      if (flags[i]&_Y_Short) {
	 int off=agetc(ttf);

	 if (!(flags[i]&_Y_Same))
	    off=-off;
	 pts[i].y=last_pos+off;
      } else if (flags[i]&_Y_Same)
	 pts[i].y=last_pos;
      else
	 pts[i].y=last_pos+(short) aget_uint16_be(ttf);
      last_pos=pts[i].y;
      if ((last_pos<gbb[1] || last_pos>gbb[3]) && (flags[i]&_On_Curve)) {
	 if (!info->gbbcomplain || (info->openflags&of_fontlint)) {
	    ErrorMsg(2,"A point in GID %d is outside the glyph bounding box\n",
		     sc->orig_pos);
	    info->bad_glyph_data=true;
	    if (!(info->openflags&of_fontlint))
	       ErrorMsg(2,"  Subsequent errors will not be reported.\n");
	    info->gbbcomplain=true;
	 }
      }
   }

   sc->layers[ly_fore].splines =
      ttfbuildcontours(path_cnt, endpt, flags, pts, info->to_order2);
   if (info->to_order2 && len != 0) {
      sc->ttf_instrs_len=len;
      sc->ttf_instrs=instructions;
   } else
      free(instructions);
   SCCategorizePoints(sc);
   free(endpt);
   free(flags);
   free(pts);
   if (afeof(ttf)) {
      ErrorMsg(2,"Reached end of file when reading simple glyph\n");
      info->bad_glyph_data=true;
   }
}

static void readttfcompositglyph(AFILE *ttf,struct ttfinfo *info,
				 SplineChar * sc, int32_t end) {
   RefChar *head=NULL, *last=NULL, *cur;
   int flags=0, arg1, arg2;
   int use_my_metrics=0;

   if (aftell(ttf) >= end) {
      ErrorMsg(2,"Empty composite %d\n", sc->orig_pos);
      info->bad_glyph_data=true;
      return;
   }

   do {
      if (aftell(ttf) >= end) {
	 ErrorMsg(2,"Bad flags value, implied MORE components at end of glyph %d\n",
		  sc->orig_pos);
	 info->bad_glyph_data=true;
	 break;
      }
      cur=RefCharCreate();
      flags=aget_uint16_be(ttf);
      cur->orig_pos=aget_uint16_be(ttf);
      if (afeof(ttf) || cur->orig_pos >= info->glyph_cnt) {
	 ErrorMsg(2,"Reference to glyph %d out of bounds when parsing 'glyf' table.\n",
		  cur->orig_pos);
	 info->bad_glyph_data=true;
	 cur->orig_pos=0;
      }
      if (info->inuse != NULL)
	 info->inuse[cur->orig_pos]=true;
      if (flags&_ARGS_ARE_WORDS) {
	 arg1=(short) aget_uint16_be(ttf);
	 arg2=(short) aget_uint16_be(ttf);
      } else {
	 arg1=(signed char) agetc(ttf);
	 arg2=(signed char) agetc(ttf);
      }
      cur->use_my_metrics=(flags&_USE_MY_METRICS)?1:0;
      if (cur->use_my_metrics) {
	 if (use_my_metrics) {
	    ErrorMsg(2,"Use-my-metrics flag set on at least two components in glyph %d\n",
		     sc->orig_pos);
	    info->bad_glyph_data=true;
	 } else
	    use_my_metrics=true;
      }
      cur->round_translation_to_grid=(flags&_ROUND)?1:0;
      if (flags&_ARGS_ARE_XY) {
	 /* There is some very strange stuff (half-)documented on the apple */
	 /*  site about how these should be interpretted when there are */
	 /*  scale factors, or rotations */
	 /* It isn't well enough described to be comprehensible */
	 /*  http://fonts.apple.com/TTRefMan/RM06/Chap6glyf.html */
	 /* Microsoft says nothing about this */
	 /* Adobe implies this is a difference between MS and Apple */
	 /*  MS doesn't do this, Apple does (GRRRGH!!!!) */
	 /* Adobe says that setting bit 12 means that this will not happen */
	 /* Adobe says that setting bit 11 means that this will happen */
	 /*  So if either bit is set we know when this happens, if neither */
	 /*  we guess... But I still don't know how to interpret the */
	 /*  apple mode under rotation... */
	 /* I notice that FreeType does nothing about rotation nor does it */
	 /*  interpret bits 11&12 */
	 /* Ah. It turns out that even Apple does not do what Apple's docs */
	 /*  claim it does. I think I've worked it out (see below), but... */
	 /*  Bleah! */
	 cur->transform[4]=arg1;
	 cur->transform[5]=arg2;
      } else {
	 /* Somehow we can get offsets by looking at the points in the */
	 /*  points so far generated and comparing them to the points in */
	 /*  the current componant */
	 /* How exactly is not described on any of the Apple, MS, Adobe */
	 /* freetype looks up arg1 in the set of points we've got so far */
	 /*  looks up arg2 in the new component (before renumbering) */
	 /*  offset.x=arg1.x-arg2.x; offset.y=arg1.y-arg2.y; */
	 /* This fixup needs to be done later though (after all glyphs */
	 /*  have been loaded) */
	 cur->match_pt_base=arg1;
	 cur->match_pt_ref=arg2;
	 cur->point_match=true;
      }
      cur->transform[0]=cur->transform[3]=1.0;
      if (flags&_SCALE)
	 cur->transform[0]=cur->transform[3]=get2dot14(ttf);
      else if (flags&_XY_SCALE) {
	 cur->transform[0]=get2dot14(ttf);
	 cur->transform[3]=get2dot14(ttf);
      } else if (flags&_MATRIX) {
	 cur->transform[0]=get2dot14(ttf);
	 cur->transform[1]=get2dot14(ttf);
	 cur->transform[2]=get2dot14(ttf);
	 cur->transform[3]=get2dot14(ttf);
      }
      if (flags&_ARGS_ARE_XY) {	/* Only muck with these guys if they are real offsets and not point matching */
#ifdef __Mac
	 /* On mac assume scaled offsets unless told unscaled explicitly */
	 if (!(flags&_UNSCALED_OFFSETS) &&
#else
	 /* everywhere else assume unscaled offsets unless told scaled explicitly */
	 if ((flags&_SCALED_OFFSETS) &&
#endif
	     (flags&_ARGS_ARE_XY)
	     && (flags&(_SCALE|_XY_SCALE|_MATRIX))) {
	    /* This is not what Apple documents on their website. But it is */
	    /*  what appears to match the behavior of their rasterizer */
	    /* Apple has changed their documentation (without updating their */
	    /*  changelog), but I believe they are still incorrect */
	    cur->transform[4] *= sqrt(cur->transform[0] * cur->transform[0] +
				      cur->transform[1] * cur->transform[1]);
	    cur->transform[5] *= sqrt(cur->transform[2] * cur->transform[2] +
				      cur->transform[3] * cur->transform[3]);
	 }
      }
      if (cur->orig_pos >= info->glyph_cnt) {
	 ErrorMsg(2,"Glyph %d attempts to reference glyph %d which is outside the font\n",
		  sc->orig_pos, cur->orig_pos);
	 chunkfree(cur, sizeof(*cur));
      } else {
	 if (head==NULL)
	    head=cur;
	 else
	    last->next=cur;
	 last=cur;
      }
      if (afeof(ttf)) {
	 ErrorMsg(2,"Reached end of file when reading composite glyph\n");
	 info->bad_glyph_data=true;
	 break;
      }
   } while (flags&_MORE);
   if ((flags&_INSTR) && info->to_order2 && aftell(ttf)<end) {
      sc->ttf_instrs_len=aget_uint16_be(ttf);
      if (sc->ttf_instrs_len>0 && aftell(ttf)+sc->ttf_instrs_len <= end) {
	 uint8_t *instructions=malloc(sc->ttf_instrs_len);
	 int i;

	 for (i=0; i<sc->ttf_instrs_len; ++i)
	    instructions[i]=agetc(ttf);
	 sc->ttf_instrs=instructions;
      } else
	 sc->ttf_instrs_len=0;
   }
   sc->layers[ly_fore].refs=head;
}

static SplineChar *readttfglyph(AFILE *ttf,struct ttfinfo *info,int start,
				int end, int gid) {
   int path_cnt;
   SplineChar *sc=SplineCharCreate(2);
   int gbb[4];

   sc->unicodeenc=-1;
   sc->vwidth=info->emsize;
   sc->orig_pos=gid;

   if (end>info->glyph_length) {
      if (!info->complainedbeyondglyfend)
	 ErrorMsg(2,"Bad glyph (%d), its definition extends beyond the end of the glyf table\n",
		  gid);
      info->bad_glyph_data=true;
      info->complainedbeyondglyfend=true;
      SplineCharFree(sc);
      return (NULL);
   } else if (end<start) {
      ErrorMsg(2,"Bad glyph (%d), its data length is negative\n", gid);
      SplineCharFree(sc);
      return (NULL);
   }

   if (start==end) {
      /* This isn't mentioned, but we seem to get some glyphs with no size, */
      /*  not even a path cnt. They appear to be empty glyphs */
      return (sc);
   }
   afseek(ttf, info->glyph_start+start, SEEK_SET);
   path_cnt=(short) aget_uint16_be(ttf);
   gbb[0]=sc->lsidebearing=(short) aget_uint16_be(ttf);
   gbb[1]=(short) aget_uint16_be(ttf);
   gbb[2]=(short) aget_uint16_be(ttf);
   gbb[3]=(short) aget_uint16_be(ttf);
   if (info->head_start != 0
       && (gbb[0]<info->fbb[0] || gbb[1]<info->fbb[1]
	   || gbb[2]>info->fbb[2] || gbb[3]>info->fbb[3])) {
      if (!info->bbcomplain || (info->openflags&of_fontlint)) {
	 ErrorMsg(2,"Glyph bounding box data exceeds font bounding box data for GID %d\n",
		  gid);
	 info->bad_glyph_data=true;
	 if (!(info->openflags&of_fontlint))
	    ErrorMsg(2,"  Subsequent errors will not be reported.\n");
	 info->bbcomplain=true;
      }
   }
   if (path_cnt >= 0)
      readttfsimpleglyph(ttf, info, sc, path_cnt, gbb);
   else
      readttfcompositglyph(ttf, info, sc, info->glyph_start+end);
   /* I don't check that composite glyphs fit in the bounding box */
   /* because the components may not have been read in yet */
   /* I'll check against the font bb later, if validation mode */
   if (start>end) {
      ErrorMsg(2,"Bad glyph (%d), disordered 'loca' table (start comes after end)\n",
	       gid);
      info->bad_glyph_data=true;
   } else if (aftell(ttf)>info->glyph_start+end) {
      ErrorMsg(2,"Bad glyph (%d), its definition extends beyond the space allowed for it\n",
	       gid);
      info->bad_glyph_data=true;
   }
   return (sc);
}

static void readttfencodings(AFILE *ttf,struct ttfinfo *info,int justinuse);

static void readttfglyphs(AFILE *ttf,struct ttfinfo *info) {
   int i, anyread;
   uint32_t *goffsets=malloc((info->glyph_cnt+1)*sizeof(uint32_t));

   /* First we read all the locations. This might not be needed, they may */
   /*  just follow one another, but nothing I've noticed says that so let's */
   /*  be careful */
   afseek(ttf, info->glyphlocations_start, SEEK_SET);
   if (info->index_to_loc_is_long) {
      for (i=0; i <= info->glyph_cnt; ++i)
	 goffsets[i]=aget_int32_be(ttf);
   } else {
      for (i=0; i <= info->glyph_cnt; ++i)
	 goffsets[i]=2*aget_uint16_be(ttf);
   }

   info->chars=calloc(info->glyph_cnt, sizeof(SplineChar *));
   if (!info->is_ttc || (info->openflags&of_all_glyphs_in_ttc)) {
      /* read all the glyphs */
      for (i=0; i<info->glyph_cnt; ++i) {
	 info->chars[i] =
	    readttfglyph(ttf, info, goffsets[i], goffsets[i+1], i);
      }
   } else {
      /* only read the glyphs we actually use in this font */
      /* this is complicated by references (and substitutions), */
      /* we can't just rely on the encoding to tell us what is used */
      info->inuse=calloc(info->glyph_cnt, sizeof(char));
      readttfencodings(ttf, info, git_justinuse);
      if (info->gsub_start != 0)	/* Some glyphs may appear in substitutions and not in the encoding... */
	 readttfgsubUsed(ttf, info);
      if (info->math_start != 0)
	 otf_read_math_used(ttf, info);
      if (info->morx_start != 0 || info->mort_start != 0)
	 readttfmort_glyphsused(ttf, info);
      anyread=true;
      while (anyread) {
	 anyread=false;
	 for (i=0; i<info->glyph_cnt; ++i) {
	    if (info->inuse[i] && info->chars[i]==NULL) {
	       info->chars[i] =
		  readttfglyph(ttf, info, goffsets[i], goffsets[i+1], i);
	       anyread=info->chars[i] != NULL;
	    }
	 }
      }
      free(info->inuse);
      info->inuse=NULL;
   }
   free(goffsets);
   for (i=0; i<info->glyph_cnt; ++i)
      if (info->chars[i] != NULL)
	 info->chars[i]->orig_pos=i;
}

/* Standard names for cff */
const char *cffnames[]={
   ".notdef",
   "space",
   "exclam",
   "quotedbl",
   "numbersign",
   "dollar",
   "percent",
   "ampersand",
   "quoteright",
   "parenleft",
   "parenright",
   "asterisk",
   "plus",
   "comma",
   "hyphen",
   "period",
   "slash",
   "zero",
   "one",
   "two",
   "three",
   "four",
   "five",
   "six",
   "seven",
   "eight",
   "nine",
   "colon",
   "semicolon",
   "less",
   "equal",
   "greater",
   "question",
   "at",
   "A",
   "B",
   "C",
   "D",
   "E",
   "F",
   "G",
   "H",
   "I",
   "J",
   "K",
   "L",
   "M",
   "N",
   "O",
   "P",
   "Q",
   "R",
   "S",
   "T",
   "U",
   "V",
   "W",
   "X",
   "Y",
   "Z",
   "bracketleft",
   "backslash",
   "bracketright",
   "asciicircum",
   "underscore",
   "quoteleft",
   "a",
   "b",
   "c",
   "d",
   "e",
   "f",
   "g",
   "h",
   "i",
   "j",
   "k",
   "l",
   "m",
   "n",
   "o",
   "p",
   "q",
   "r",
   "s",
   "t",
   "u",
   "v",
   "w",
   "x",
   "y",
   "z",
   "braceleft",
   "bar",
   "braceright",
   "asciitilde",
   "exclamdown",
   "cent",
   "sterling",
   "fraction",
   "yen",
   "florin",
   "section",
   "currency",
   "quotesingle",
   "quotedblleft",
   "guillemotleft",
   "guilsinglleft",
   "guilsinglright",
   "fi",
   "fl",
   "endash",
   "dagger",
   "daggerdbl",
   "periodcentered",
   "paragraph",
   "bullet",
   "quotesinglbase",
   "quotedblbase",
   "quotedblright",
   "guillemotright",
   "ellipsis",
   "perthousand",
   "questiondown",
   "grave",
   "acute",
   "circumflex",
   "tilde",
   "macron",
   "breve",
   "dotaccent",
   "dieresis",
   "ring",
   "cedilla",
   "hungarumlaut",
   "ogonek",
   "caron",
   "emdash",
   "AE",
   "ordfeminine",
   "Lslash",
   "Oslash",
   "OE",
   "ordmasculine",
   "ae",
   "dotlessi",
   "lslash",
   "oslash",
   "oe",
   "germandbls",
   "onesuperior",
   "logicalnot",
   "mu",
   "trademark",
   "Eth",
   "onehalf",
   "plusminus",
   "Thorn",
   "onequarter",
   "divide",
   "brokenbar",
   "degree",
   "thorn",
   "threequarters",
   "twosuperior",
   "registered",
   "minus",
   "eth",
   "multiply",
   "threesuperior",
   "copyright",
   "Aacute",
   "Acircumflex",
   "Adieresis",
   "Agrave",
   "Aring",
   "Atilde",
   "Ccedilla",
   "Eacute",
   "Ecircumflex",
   "Edieresis",
   "Egrave",
   "Iacute",
   "Icircumflex",
   "Idieresis",
   "Igrave",
   "Ntilde",
   "Oacute",
   "Ocircumflex",
   "Odieresis",
   "Ograve",
   "Otilde",
   "Scaron",
   "Uacute",
   "Ucircumflex",
   "Udieresis",
   "Ugrave",
   "Yacute",
   "Ydieresis",
   "Zcaron",
   "aacute",
   "acircumflex",
   "adieresis",
   "agrave",
   "aring",
   "atilde",
   "ccedilla",
   "eacute",
   "ecircumflex",
   "edieresis",
   "egrave",
   "iacute",
   "icircumflex",
   "idieresis",
   "igrave",
   "ntilde",
   "oacute",
   "ocircumflex",
   "odieresis",
   "ograve",
   "otilde",
   "scaron",
   "uacute",
   "ucircumflex",
   "udieresis",
   "ugrave",
   "yacute",
   "ydieresis",
   "zcaron",
   "exclamsmall",
   "Hungarumlautsmall",
   "dollaroldstyle",
   "dollarsuperior",
   "ampersandsmall",
   "Acutesmall",
   "parenleftsuperior",
   "parenrightsuperior",
   "twodotenleader",
   "onedotenleader",
   "zerooldstyle",
   "oneoldstyle",
   "twooldstyle",
   "threeoldstyle",
   "fouroldstyle",
   "fiveoldstyle",
   "sixoldstyle",
   "sevenoldstyle",
   "eightoldstyle",
   "nineoldstyle",
   "commasuperior",
   "threequartersemdash",
   "periodsuperior",
   "questionsmall",
   "asuperior",
   "bsuperior",
   "centsuperior",
   "dsuperior",
   "esuperior",
   "isuperior",
   "lsuperior",
   "msuperior",
   "nsuperior",
   "osuperior",
   "rsuperior",
   "ssuperior",
   "tsuperior",
   "ff",
   "ffi",
   "ffl",
   "parenleftinferior",
   "parenrightinferior",
   "Circumflexsmall",
   "hyphensuperior",
   "Gravesmall",
   "Asmall",
   "Bsmall",
   "Csmall",
   "Dsmall",
   "Esmall",
   "Fsmall",
   "Gsmall",
   "Hsmall",
   "Ismall",
   "Jsmall",
   "Ksmall",
   "Lsmall",
   "Msmall",
   "Nsmall",
   "Osmall",
   "Psmall",
   "Qsmall",
   "Rsmall",
   "Ssmall",
   "Tsmall",
   "Usmall",
   "Vsmall",
   "Wsmall",
   "Xsmall",
   "Ysmall",
   "Zsmall",
   "colonmonetary",
   "onefitted",
   "rupiah",
   "Tildesmall",
   "exclamdownsmall",
   "centoldstyle",
   "Lslashsmall",
   "Scaronsmall",
   "Zcaronsmall",
   "Dieresissmall",
   "Brevesmall",
   "Caronsmall",
   "Dotaccentsmall",
   "Macronsmall",
   "figuredash",
   "hypheninferior",
   "Ogoneksmall",
   "Ringsmall",
   "Cedillasmall",
   "questiondownsmall",
   "oneeighth",
   "threeeighths",
   "fiveeighths",
   "seveneighths",
   "onethird",
   "twothirds",
   "zerosuperior",
   "foursuperior",
   "fivesuperior",
   "sixsuperior",
   "sevensuperior",
   "eightsuperior",
   "ninesuperior",
   "zeroinferior",
   "oneinferior",
   "twoinferior",
   "threeinferior",
   "fourinferior",
   "fiveinferior",
   "sixinferior",
   "seveninferior",
   "eightinferior",
   "nineinferior",
   "centinferior",
   "dollarinferior",
   "periodinferior",
   "commainferior",
   "Agravesmall",
   "Aacutesmall",
   "Acircumflexsmall",
   "Atildesmall",
   "Adieresissmall",
   "Aringsmall",
   "AEsmall",
   "Ccedillasmall",
   "Egravesmall",
   "Eacutesmall",
   "Ecircumflexsmall",
   "Edieresissmall",
   "Igravesmall",
   "Iacutesmall",
   "Icircumflexsmall",
   "Idieresissmall",
   "Ethsmall",
   "Ntildesmall",
   "Ogravesmall",
   "Oacutesmall",
   "Ocircumflexsmall",
   "Otildesmall",
   "Odieresissmall",
   "OEsmall",
   "Oslashsmall",
   "Ugravesmall",
   "Uacutesmall",
   "Ucircumflexsmall",
   "Udieresissmall",
   "Yacutesmall",
   "Thornsmall",
   "Ydieresissmall",
   "001.000",
   "001.001",
   "001.002",
   "001.003",
   "Black",
   "Bold",
   "Book",
   "Light",
   "Medium",
   "Regular",
   "Roman",
   "Semibold",
   NULL
};

const int nStdStrings=sizeof(cffnames)/sizeof(cffnames[0])-1;

static char **readcfffontnames(AFILE *ttf,int *cnt,struct ttfinfo *info) {
   uint16_t count=aget_uint16_be(ttf);
   int offsize;
   uint32_t *offsets;
   char **names;
   int i, j;

   if (cnt != NULL)
      *cnt=count;

   if (count==0)
      return (NULL);
   offsets=malloc((count+1)*sizeof(uint32_t));
   offsize=agetc(ttf);
   for (i=0; i <= count; ++i)
      offsets[i]=getoffset(ttf, offsize);
   names=malloc((count+1)*sizeof(char *));
   for (i=0; i<count; ++i) {
      if (offsets[i+1]<offsets[i]) {
/* GT: The CFF font type contains a thing called a name INDEX, and that INDEX */
/* GT: is bad. It is an index of many of the names used in the CFF font. */
/* GT: We hope the user will never see this. */
	 ErrorMsg(2,"Bad CFF name INDEX\n");
	 if (info != NULL)
	    info->bad_cff=true;
	 while (i<count) {
	    names[i]=fastrdup("");
	    ++i;
	 }
	 --i;
      } else {
	 names[i]=malloc(offsets[i+1]-offsets[i]+1);
	 for (j=0; j<offsets[i+1]-offsets[i]; ++j)
	    names[i][j]=agetc(ttf);
	 names[i][j]='\0';
      }
   }
   names[i]=NULL;
   free(offsets);
   return (names);
}

static char *addnibble(char *pt,int nib) {
   if (nib <= 9)
      *pt++=nib+'0';
   else if (nib==10)
      *pt++='.';
   else if (nib==11)
      *pt++='E';
   else if (nib==12) {
      *pt++='E';
      *pt++='-';
   } else if (nib==14)
      *pt++='-';
   else if (nib==15)
      *pt++='\0';
   return (pt);
}

static int readcffthing(AFILE *ttf,int *_ival,double *dval,int *operand,
			struct ttfinfo *info) {
   char buffer[50], *pt;
   int ch, ival;

   ch=agetc(ttf);
   if (ch==12) {
      *operand=(12 << 8)|agetc(ttf);
      return (3);
   } else if (ch <= 21) {
      *operand=ch;
      return (3);
   } else if (ch==30) {
      /* fixed format doesn't exist in dict data but does in type2 strings */
      pt=buffer;
      do {
	 ch=agetc(ttf);
	 if (pt<buffer+44 || (ch&0xf)==0xf || (ch&0xf0)==0xf0) {
	    pt=addnibble(pt, ch >> 4);
	    pt=addnibble(pt, ch&0xf);
	 }
      } while (pt[-1] != '\0');
      *dval=strtod(buffer, NULL);
      return (2);
   } else if (ch >= 32 && ch <= 246) {
      *_ival=ch-139;
      return (1);
   } else if (ch >= 247 && ch <= 250) {
      *_ival=((ch-247) << 8)+agetc(ttf)+108;
      return (1);
   } else if (ch >= 251 && ch <= 254) {
      *_ival=-((ch-251) << 8)-agetc(ttf)-108;
      return (1);
   } else if (ch==28) {
      ival=agetc(ttf) << 8;
      *_ival=(short) (ival|agetc(ttf));
      return (1);
   } else if (ch==29) {
      /* 4 byte integers exist in dict data but not in type2 strings */
      ival=agetc(ttf) << 24;
      ival=ival|agetc(ttf) << 16;
      ival=ival|agetc(ttf) << 8;
      *_ival=(int) (ival|agetc(ttf));
      return (1);
   }
   ErrorMsg(2,"Unexpected value in dictionary %d\n", ch);
   info->bad_cff=true;
   *_ival=0;
   return (0);
}

static void skipcfft2thing(AFILE *ttf) {
   /* The old CFF spec allows little type2 programs to live in the CFF dict */
   /*  indices. These are designed to allow interpolation of values for mm */
   /*  fonts. */
   /* The Type2 program is terminated by an "endchar" operator */
   /* I don't support this, but I shall try to skip over them properly */
   /* There's no discussion about how values move from the t2 stack to the */
   /*  cff stack, as there are no examples of this, it's hard to guess */
   int ch;

/* GT: DICT is a magic term inside CFF fonts, as is INDEX, and I guess CFF and type2 */
   ErrorMsg(2,"FontAnvil does not support type2 programs embedded in CFF DICT INDICES.\n");
   while (1) {
      ch=agetc(ttf);
      if (ch >= 247 && ch <= 254)
	 agetc(ttf);		/* Two byte number */
      else if (ch==255) {
	 agetc(ttf);
	 agetc(ttf);
	 agetc(ttf);
	 agetc(ttf);
	 /* 16.16 number */
      } else if (ch==28) {
	 agetc(ttf);
	 agetc(ttf);
      } else if (ch==12) {
	 agetc(ttf);		/* Two byte operator */
      } else if (ch==14) {
	 return;
      }
   }
}

struct topdicts {
   int32_t cff_start;
   char *fontname;		/* From Name Index */
   int version;			/* SID */
   int notice;			/* SID */
   int copyright;		/* SID */
   int fullname;		/* SID */
   int familyname;		/* SID */
   int weight;			/* SID */
   int isfixedpitch;
   double italicangle;
   double underlinepos;
   double underlinewidth;
   int painttype;
   int charstringtype;
   double fontmatrix[6];
   int fontmatrix_set;
   int uniqueid;
   double fontbb[4];
   double strokewidth;
   int xuid[20];
   int charsetoff;		/* from start of file */
   int encodingoff;		/* from start of file */
   int charstringsoff;		/* from start of file */
   int private_size;
   int private_offset;		/* from start of file */
   int synthetic_base;		/* font index */
   int postscript_code;		/* SID */
   /* synthetic fonts only (whatever they are) */
   int basefontname;		/* SID */
   /* Multiple master/synthetic fonts */
   double basefontblend[16];	/* delta */ /* No description of why this is relevant for mm fonts */
   /* Multiple master fonts only */
   int blendaxistypes[17];	/* SID */
   int nMasters;
   int nAxes;
   double weightvector[17];
   int lenBuildCharArray;	/* No description of what this means */
   int NormalizeDesignVector;	/* SID */ /* No description of what this does */
   int ConvertDesignVector;	/* SID */ /* No description of what this does */
   /* CID fonts only */
   int ros_registry;		/* SID */
   int ros_ordering;		/* SID */
   int ros_supplement;
   double cidfontversion;
   int cidfontrevision;
   int cidfonttype;
   int cidcount;
   int uidbase;
   int fdarrayoff;		/* from start of file */
   int fdselectoff;		/* from start of file */
   int sid_fontname;		/* SID */
/* Private stuff */
   double bluevalues[14];
   double otherblues[10];
   double familyblues[14];
   double familyotherblues[10];
   double bluescale;
   double blueshift;
   double bluefuzz;
   int stdhw;
   int stdvw;
   double stemsnaph[10];
   double stemsnapv[10];
   int forcebold;
   double forceboldthreshold;
   int languagegroup;
   double expansionfactor;
   int initialRandomSeed;
   int subrsoff;		/* from start of this private table */
   int defaultwidthx;
   int nominalwidthx;
   struct pschars glyphs;
   struct pschars local_subrs;
   uint16_t *charset;
};

static void TopDictFree(struct topdicts *dict) {
   int i;

   free(dict->charset);
   for (i=0; i<dict->glyphs.cnt; ++i)
      free(dict->glyphs.values[i]);
   free(dict->glyphs.values);
   free(dict->glyphs.lens);
   for (i=0; i<dict->local_subrs.cnt; ++i)
      free(dict->local_subrs.values[i]);
   free(dict->local_subrs.values);
   free(dict->local_subrs.lens);
   free(dict);
}

static void readcffsubrs(AFILE *ttf,struct pschars *subs,
			 struct ttfinfo *info) {
   uint16_t count=aget_uint16_be(ttf);
   int offsize;
   uint32_t *offsets;
   int i, j, base;
   int err=false;

   memset(subs, '\0', sizeof(struct pschars));
   if (count==0)
      return;
   subs->cnt=count;
   subs->lens=malloc(count * sizeof(int));
   subs->values=malloc(count * sizeof(uint8_t *));
   offsets=malloc((count+1)*sizeof(uint32_t));
   offsize=agetc(ttf);
   for (i=0; i <= count; ++i)
      offsets[i]=getoffset(ttf, offsize);
   base=aftell(ttf)-1;
   for (i=0; i<count; ++i) {
      if (offsets[i+1]>offsets[i]
	  && offsets[i+1]-offsets[i]<0x10000) {
	 subs->lens[i]=offsets[i+1]-offsets[i];
	 subs->values[i]=malloc(offsets[i+1]-offsets[i]+1);
	 for (j=0; j<offsets[i+1]-offsets[i]; ++j)
	    subs->values[i][j]=agetc(ttf);
	 subs->values[i][j]='\0';
      } else {
	 if (!err)
	    ErrorMsg(2,"Bad subroutine INDEX in cff font.\n");
	 info->bad_cff=true;
	 err=true;
	 subs->lens[i]=1;
	 subs->values[i]=malloc(2);
	 subs->values[i][0]=11;	/* return */
	 subs->values[i][1]='\0';
	 afseek(ttf, base+offsets[i+1], SEEK_SET);
      }
   }
   free(offsets);
}

static struct topdicts *readcfftopdict(AFILE *ttf,char *fontname,int len,
				       struct ttfinfo *info) {
   struct topdicts *td=calloc(1, sizeof(struct topdicts));
   long base=aftell(ttf);
   int ival, oval, sp, ret, i;
   double stack[50];

   if (fontname != NULL)
      ValidatePostScriptFontName(info, fontname);

   td->fontname=fontname;
   td->underlinepos=-100;
   td->underlinewidth=50;
   td->charstringtype=2;
   td->fontmatrix[0]=td->fontmatrix[3]=.001;

   td->notice=td->copyright=td->fullname=td->familyname=td->weight =
      td->version=-1;
   td->postscript_code=td->basefontname=-1;
   td->synthetic_base=td->ros_registry=-1;
   td->fdarrayoff=td->fdselectoff=td->sid_fontname=-1;
   td->blendaxistypes[0]=-1;

   /* Multiple master fonts can have Type2 operators here, particularly */
   /*  blend operators. We're ignoring that */
   while (aftell(ttf)<base+len) {
      sp=0;
      while ((ret=readcffthing(ttf, &ival, &stack[sp], &oval, info)) != 3
	     && aftell(ttf)<base+len) {
	 if (ret==1)
	    stack[sp]=ival;
	 if (ret != 0 && sp<45)
	    ++sp;
      }
      if (ret==3 && oval==31 /* "T2" operator, can have 0 arguments */ ) {
	 skipcfft2thing(ttf);
      } else if (sp==0) {
	 ErrorMsg(2,"No argument to operator\n");
	 info->bad_cff=true;
      } else if (ret==3)
	 switch (oval) {
	   case 0:
	      td->version=stack[sp-1];
	      break;
	   case 1:
	      td->notice=stack[sp-1];
	      break;
	   case (12 << 8)+0:
	      td->copyright=stack[sp-1];
	      break;
	   case 2:
	      td->fullname=stack[sp-1];
	      break;
	   case 3:
	      td->familyname=stack[sp-1];
	      break;
	   case 4:
	      td->weight=stack[sp-1];
	      break;
	   case (12 << 8)+1:
	      td->isfixedpitch=stack[sp-1];
	      break;
	   case (12 << 8)+2:
	      td->italicangle=stack[sp-1];
	      break;
	   case (12 << 8)+3:
	      td->underlinepos=stack[sp-1];
	      break;
	   case (12 << 8)+4:
	      td->underlinewidth=stack[sp-1];
	      break;
	   case (12 << 8)+5:
	      td->painttype=stack[sp-1];
	      break;
	   case (12 << 8)+6:
	      td->charstringtype=stack[sp-1];
	      break;
	   case (12 << 8)+7:
	      memcpy(td->fontmatrix, stack,
		     (sp >= 6?6:sp)*sizeof(double));
	      td->fontmatrix_set=1;
	      break;
	   case 13:
	      td->uniqueid=stack[sp-1];
	      break;
	   case 5:
	      memcpy(td->fontbb, stack, (sp >= 4?4:sp)*sizeof(double));
	      break;
	   case (12 << 8)+8:
	      td->strokewidth=stack[sp-1];
	      break;
	   case 14:
	      for (i=0; i<sp && i<20; ++i)
		 td->xuid[i]=stack[i];
	      break;
	   case 15:
	      td->charsetoff=stack[sp-1];
	      break;
	   case 16:
	      td->encodingoff=stack[sp-1];
	      break;
	   case 17:
	      td->charstringsoff=stack[sp-1];
	      break;
	   case 18:
	      td->private_size=stack[0];
	      td->private_offset=stack[1];
	      break;
	   case (12 << 8)+20:
	      ErrorMsg(2,"FontAnvil does not support synthetic fonts\n");
	      td->synthetic_base=stack[sp-1];
	      break;
	   case (12 << 8)+21:
	      td->postscript_code=stack[sp-1];
	      break;
	   case (12 << 8)+22:
	      td->basefontname=stack[sp-1];
	      break;
	   case (12 << 8)+23:
	      for (i=0; i<sp && i<16; ++i)
		 td->basefontblend[i]=stack[i];
	      break;
	   case (12 << 8)+24:
	      ErrorMsg(2,"FontAnvil does not support type2 multiple master fonts\n");
	      info->bad_cff=true;
	      td->nMasters=stack[0];
	      td->nAxes=sp-4;
	      memcpy(td->weightvector, stack+1, (sp-4)*sizeof(double));
	      td->lenBuildCharArray=stack[sp-3];
	      td->NormalizeDesignVector=stack[sp-2];	/* These are type2 charstrings, even in type1 fonts */
	      td->ConvertDesignVector=stack[sp-1];
	      break;
	   case (12 << 8)+26:
	      for (i=0; i<sp && i<16; ++i)
		 td->blendaxistypes[i]=stack[i];
	      td->blendaxistypes[i]=-1;
	      break;
	   case (12 << 8)+30:
	      td->ros_registry=stack[0];
	      td->ros_ordering=stack[1];
	      td->ros_supplement=stack[2];
	      break;
	   case (12 << 8)+31:
	      td->cidfontversion=stack[sp-1];
	      break;
	   case (12 << 8)+32:
	      td->cidfontrevision=stack[sp-1];
	      break;
	   case (12 << 8)+33:
	      td->cidfonttype=stack[sp-1];
	      break;
	   case (12 << 8)+34:
	      td->cidcount=stack[sp-1];
	      break;
	   case (12 << 8)+35:
	      td->uidbase=stack[sp-1];
	      break;
	   case (12 << 8)+36:
	      td->fdarrayoff=stack[sp-1];
	      break;
	   case (12 << 8)+37:
	      td->fdselectoff=stack[sp-1];
	      break;
	   case (12 << 8)+38:
	      td->sid_fontname=stack[sp-1];
	      break;
	   case (12 << 8)+39:
	      ErrorMsg(2,"FontAnvil does not support Chameleon fonts\n");;
	      break;
	   default:
	      ErrorMsg(2,"Unknown operator in %s: %x\n", fontname, oval);
	      info->bad_cff=true;
	      break;
	 }
   }
   return (td);
}

static void readcffprivate(AFILE *ttf,struct topdicts *td,
			   struct ttfinfo *info) {
   int ival, oval, sp, ret, i;
   double stack[50];
   int32_t end=td->cff_start+td->private_offset+td->private_size;

   afseek(ttf, td->cff_start+td->private_offset, SEEK_SET);

   td->subrsoff=-1;
   td->expansionfactor=.06;
   td->bluefuzz=1;
   td->blueshift=7;
   td->bluescale=.039625;

   while (aftell(ttf)<end) {
      if (afeof(ttf)) {
	 ErrorMsg(2,"End of file found when reading private dictionary.\n");
	 break;
      }
      sp=0;
      while ((ret=readcffthing(ttf, &ival, &stack[sp], &oval, info)) != 3
	     && aftell(ttf)<end) {
	 if (ret==1)
	    stack[sp]=ival;
	 if (ret != 0 && sp<45)
	    ++sp;
      }
      if (ret==3 && oval==31 /* "T2" operator, can have 0 arguments */ ) {
	 skipcfft2thing(ttf);
      } else if (sp==0 && oval != 6 && oval != 7 && oval != 8 && oval != 9
		 && oval != (12 << 8)+12 && oval != (12 << 8)+13) {
	 ErrorMsg(2,"No argument to operator %d in private dict\n", oval);
	 info->bad_cff=true;
      } else if (ret==3)
	 switch (oval) {
	   case 6:
	      for (i=0; i<sp && i<14; ++i) {
		 td->bluevalues[i]=stack[i];
		 if (i != 0)
		    td->bluevalues[i] += td->bluevalues[i-1];
	      }
	      if (i==0)
		 td->bluevalues[0]=1234567;	/* Marker for an empty arry, which is legal, and different from no array */
	      break;
	   case 7:
	      for (i=0; i<sp && i<10; ++i) {
		 td->otherblues[i]=stack[i];
		 if (i != 0)
		    td->otherblues[i] += td->otherblues[i-1];
	      }
	      if (i==0)
		 td->otherblues[0]=1234567;
	      break;
	   case 8:
	      for (i=0; i<sp && i<14; ++i) {
		 td->familyblues[i]=stack[i];
		 if (i != 0)
		    td->familyblues[i] += td->familyblues[i-1];
	      }
	      if (i==0)
		 td->familyblues[0]=1234567;
	      break;
	   case 9:
	      for (i=0; i<sp && i<10; ++i) {
		 td->familyotherblues[i]=stack[i];
		 if (i != 0)
		    td->familyotherblues[i] += td->familyotherblues[i-1];
	      }
	      if (i==0)
		 td->familyotherblues[0]=1234567;
	      break;
	   case (12 << 8)+9:
	      td->bluescale=stack[sp-1];
	      break;
	   case (12 << 8)+10:
	      td->blueshift=stack[sp-1];
	      break;
	   case (12 << 8)+11:
	      td->bluefuzz=stack[sp-1];
	      break;
	   case 10:
	      td->stdhw=stack[sp-1];
	      break;
	   case 11:
	      td->stdvw=stack[sp-1];
	      break;
	   case (12 << 8)+12:
	      for (i=0; i<sp && i<10; ++i) {
		 td->stemsnaph[i]=stack[i];
		 if (i != 0)
		    td->stemsnaph[i] += td->stemsnaph[i-1];
	      }
	      if (i==0)
		 td->stemsnaph[0]=1234567;
	      break;
	   case (12 << 8)+13:
	      for (i=0; i<sp && i<10; ++i) {
		 td->stemsnapv[i]=stack[i];
		 if (i != 0)
		    td->stemsnapv[i] += td->stemsnapv[i-1];
	      }
	      if (i==0)
		 td->stemsnapv[0]=1234567;
	      break;
	   case (12 << 8)+14:
	      td->forcebold=stack[sp-1];
	      break;
	   case (12 << 8)+15:	/* obsolete */
	      td->forceboldthreshold=stack[sp-1];
	      break;
	   case (12 << 8)+16:
	      /* lenIV. -1 => unencrypted charstrings */
	      /* obsolete */
	      break;
	   case (12 << 8)+17:
	      td->languagegroup=stack[sp-1];
	      break;
	   case (12 << 8)+18:
	      td->expansionfactor=stack[sp-1];
	      break;
	   case (12 << 8)+19:
	      td->initialRandomSeed=stack[sp-1];
	      break;
	   case 19:
	      td->subrsoff=stack[sp-1];
	      break;
	   case 20:
	      td->defaultwidthx=stack[sp-1];
	      break;
	   case 21:
	      td->nominalwidthx=stack[sp-1];
	      break;
	   default:
	      ErrorMsg(2,"Unknown operator in %s: %x\n", td->fontname, oval);
	      info->bad_cff=true;
	      break;
	 }
   }

   if (td->subrsoff != -1) {
      afseek(ttf, td->cff_start+td->private_offset+td->subrsoff, SEEK_SET);
      readcffsubrs(ttf, &td->local_subrs, info);
   }
}

static struct topdicts **readcfftopdicts(AFILE *ttf,char **fontnames,
					 int32_t cff_start,
					 struct ttfinfo *info,
					 struct topdicts *parent_dict) {
   uint16_t count=aget_uint16_be(ttf);
   int offsize;
   uint32_t *offsets;
   struct topdicts **dicts;
   int i;

   if (count==0)
      return (NULL);
   offsets=malloc((count+1)*sizeof(uint32_t));
   offsize=agetc(ttf);
   for (i=0; i <= count; ++i)
      offsets[i]=getoffset(ttf, offsize);
   dicts=malloc((count+1)*sizeof(struct topdicts *));
   for (i=0; i<count; ++i) {
      dicts[i]=readcfftopdict(ttf, fontnames != NULL?fontnames[i]:NULL,
				offsets[i+1]-offsets[i], info);
      if (parent_dict != NULL && parent_dict->fontmatrix_set) {
	 MatMultiply(parent_dict->fontmatrix, dicts[i]->fontmatrix,
		     dicts[i]->fontmatrix);
      }
      dicts[i]->cff_start=cff_start;
   }
   dicts[i]=NULL;
   free(offsets);
   return (dicts);
}

static const char *getsid(int sid,char **strings,int scnt,
			  struct ttfinfo *info) {
   if (sid==-1)
      return (NULL);
   else if (sid<nStdStrings)
      return (cffnames[sid]);
   else if (sid-nStdStrings>scnt) {
      ErrorMsg(2,"Bad sid %d (must be less than %d)\n", sid,
	       scnt+nStdStrings);
      if (info != NULL)
	 info->bad_cff=true;
      return (NULL);
   } else
      return (strings[sid-nStdStrings]);
}

/* I really expect to deal with encodings in ttf cmap, but ocasionally we */
/*  get a bare cff */
static void readcffenc(AFILE *ttf,struct topdicts *dict,
		       struct ttfinfo *info, char **strings, int scnt) {
   int format, cnt, i, j, pos, first, last, dupenc, sid;
   extern char *AdobeStandardEncoding[], *AdobeExpertEncoding[];
   const char *name;
   EncMap *map;

   if (info->encoding_start != 0)	/* Use the cmap instead */
      return;
   if (info->subfontcnt != 0)
      return;			/* Use cids instead */

   for (i=0; i<info->glyph_cnt; ++i) {
      if (info->chars[i]->unicodeenc==-1)
	 info->chars[i]->unicodeenc =
	    UniFromName(info->chars[i]->name, ui_none, &custom);
   }

   map=EncMapNew(256, 256, &custom);
   if (dict->encodingoff==0 || dict->encodingoff==1) {
      /* Standard Encodings */
      char **enc =
	 dict->encodingoff==0?AdobeStandardEncoding:AdobeExpertEncoding;
      map->enc =
	 FindOrMakeEncoding(dict->encodingoff ==
			    0?"AdobeStandard":"Custom");
      if (map->enc==NULL)
	 map->enc=&custom;
      for (i=0; i<info->glyph_cnt; ++i) {
	 for (pos=0; pos<256; ++pos)
	    if (strcmp(info->chars[i]->name, enc[pos])==0)
	       break;
	 if (pos<256)
	    map->map[pos]=i;
      }
   } else {
      afseek(ttf, dict->cff_start+dict->encodingoff, SEEK_SET);
      format=agetc(ttf);
      if ((format&0x7f)==0) {
	 cnt=agetc(ttf);
	 for (i=1; i <= cnt && i<info->glyph_cnt; ++i)
	    map->map[agetc(ttf)]=i;
      } else if ((format&0x7f)==1) {
	 cnt=agetc(ttf);
	 pos=0;
	 for (i=0; i<cnt; ++i) {
	    first=agetc(ttf);
	    last=first+agetc(ttf)-1;
	    while (first <= last && first<256) {
	       if (pos<info->glyph_cnt)
		  map->map[first]=pos;
	       ++pos;
	       ++first;
	    }
	 }
      } else {
	 ErrorMsg(2,"Unexpected encoding format in cff: %d\n", format);
	 if (info != NULL)
	    info->bad_cff=true;
      }
      if (format&0x80) {
	 cnt=agetc(ttf);
	 for (i=0; i<cnt; ++i) {
	    dupenc=agetc(ttf);
	    sid=aget_uint16_be(ttf);
	    name=getsid(sid, strings, scnt, info);
	    if (name==NULL)	/* Table is erroneous */
	       break;
	    for (j=0; j<info->glyph_cnt; ++j)
	       if (strcmp(name, info->chars[j]->name)==0)
		  break;
	    if (j != info->glyph_cnt)
	       map->map[dupenc]=j;
	 }
      }
   }
   info->map=map;
}

static void readcffset(AFILE *ttf,struct topdicts *dict,
		       struct ttfinfo *info) {
   int len=dict->glyphs.cnt;
   int i;
   int format, cnt, j, first;

   i=0;
   if (dict->charsetoff==0) {
      /* ISO Adobe charset */
      dict->charset=malloc(len * sizeof(uint16_t));
      for (i=0; i<len && i <= 228; ++i)
	 dict->charset[i]=i;
   } else if (dict->charsetoff==1) {
      /* Expert charset */
      dict->charset=malloc((len<162?162:len)*sizeof(uint16_t));
      dict->charset[0]=0;	/* .notdef */
      dict->charset[1]=1;
      for (i=2; i<len && i <= 238-227; ++i)
	 dict->charset[i]=i+227;
      dict->charset[12]=13;
      dict->charset[13]=14;
      dict->charset[14]=15;
      dict->charset[15]=99;
      for (i=16; i<len && i <= 248-223; ++i)
	 dict->charset[i]=i+223;
      dict->charset[25]=27;
      dict->charset[26]=28;
      for (i=27; i<len && i <= 266-222; ++i)
	 dict->charset[i]=i+222;
      dict->charset[44]=109;
      dict->charset[45]=110;
      for (i=46; i<len && i <= 318-221; ++i)
	 dict->charset[i]=i+221;
      dict->charset[96]=158;
      dict->charset[97]=155;
      dict->charset[98]=163;
      for (i=99; i<len && i <= 326-220; ++i)
	 dict->charset[i]=i+220;
      dict->charset[107]=150;
      dict->charset[108]=164;
      dict->charset[109]=169;
      for (i=110; i<len && i <= 378-217; ++i)
	 dict->charset[i]=i+217;
   } else if (dict->charsetoff==2) {
      /* Expert subset charset */
      dict->charset=malloc((len<130?130:len)*sizeof(uint16_t));
      dict->charset[0]=0;	/* .notdef */
      dict->charset[1]=1;
      for (i=2; i<len && i <= 238-227; ++i)
	 dict->charset[i]=i+227;
      dict->charset[12]=13;
      dict->charset[13]=14;
      dict->charset[14]=15;
      dict->charset[15]=99;
      for (i=16; i<len && i <= 248-223; ++i)
	 dict->charset[i]=i+223;
      dict->charset[25]=27;
      dict->charset[26]=28;
      for (i=27; i<len && i <= 266-222; ++i)
	 dict->charset[i]=i+222;
      dict->charset[44]=109;
      dict->charset[45]=110;
      for (i=46; i<len && i <= 272-221; ++i)
	 dict->charset[i]=i+221;
      dict->charset[51]=300;
      dict->charset[52]=301;
      dict->charset[53]=302;
      dict->charset[54]=305;
      dict->charset[55]=314;
      dict->charset[56]=315;
      dict->charset[57]=158;
      dict->charset[58]=155;
      dict->charset[59]=163;
      for (i=60; i<len && i <= 326-260; ++i)
	 dict->charset[i]=i+260;
      dict->charset[67]=150;
      dict->charset[68]=164;
      dict->charset[69]=169;
      for (i=110; i<len && i <= 346-217; ++i)
	 dict->charset[i]=i+217;
   } else {
      dict->charset=malloc(len * sizeof(uint16_t));
      dict->charset[0]=0;	/* .notdef */
      afseek(ttf, dict->cff_start+dict->charsetoff, SEEK_SET);
      format=agetc(ttf);
      if (format==0) {
	 for (i=1; i<len; ++i)
	    dict->charset[i]=aget_uint16_be(ttf);
      } else if (format==1) {
	 for (i=1; i<len;) {
	    first=dict->charset[i++]=aget_uint16_be(ttf);
	    cnt=agetc(ttf);
	    for (j=0; j<cnt; ++j)
	       dict->charset[i++]=++first;
	 }
      } else if (format==2) {
	 for (i=1; i<len;) {
	    first=dict->charset[i++]=aget_uint16_be(ttf);
	    cnt=aget_uint16_be(ttf);
	    for (j=0; j<cnt; ++j)
	       dict->charset[i++]=++first;
	 }
      } else {
	 ErrorMsg(2,"Unexpected charset format in cff: %d\n", format);
	 if (info != NULL)
	    info->bad_cff=true;
      }
   }
   while (i<len)
      dict->charset[i++]=0;
}

static uint8_t *readfdselect(AFILE *ttf,int numglyphs,struct ttfinfo *info) {
   uint8_t *fdselect=calloc(numglyphs, sizeof(uint8_t));
   int i, j, format, nr, first, end, fd;

   format=agetc(ttf);
   if (format==0) {
      for (i=0; i<numglyphs; ++i)
	 fdselect[i]=agetc(ttf);
   } else if (format==3) {
      nr=aget_uint16_be(ttf);
      first=aget_uint16_be(ttf);
      for (i=0; i<nr; ++i) {
	 fd=agetc(ttf);
	 end=aget_uint16_be(ttf);
	 for (j=first; j<end; ++j) {
	    if (j >= numglyphs) {
	       ErrorMsg(2,"Bad fdselect\n");
	       if (info != NULL)
		  info->bad_cff=true;
	    } else
	       fdselect[j]=fd;
	 }
	 first=end;
      }
   } else {
      ErrorMsg(2,"Didn't understand format for fdselect %d\n", format);
      if (info != NULL)
	 info->bad_cff=true;
   }
   return (fdselect);
}


static char *intarray2str(int *array,int size) {
   int i, j;
   char *pt, *ret;

   for (i=size-1; i >= 0 && array[i]==0; --i);
   if (i==-1)
      return (NULL);
   ret=pt=malloc((i+1)*12+12);
   *pt++='[';
   for (j=0; j <= i; ++j) {
      sprintf(pt, "%d ", array[j]);
      pt += strlen(pt);
   }
   pt[-1]=']';
   return (ret);
}

static char *realarray2str(double *array,int size,int must_be_even) {
   int i, j;
   char *pt, *ret;

   for (i=size-1; i >= 0 && array[i]==0; --i);
   if (i==-1)
      return (NULL);
   if (i==0 && array[0]==1234567)	/* Special marker for a null array */
      return (fastrdup("[]"));
   if (must_be_even && !(i&1) && array[i]<0)
      ++i;			/* Someone gave us a bluevalues of [-20 0] and we reported [-20] */
   ret=pt=malloc((i+1)*20+12);
   *pt++='[';
   for (j=0; j <= i; ++j) {
      sprintf(pt, "%g ", (double) array[j]);
      pt += strlen(pt);
   }
   pt[-1]=']';
   return (ret);
}

static void privateadd(struct psdict *private,char *key,char *value) {
   if (value==NULL)
      return;
   private->keys[private->next]=fastrdup(key);
   private->values[private->next++]=value;
}

static void privateaddint(struct psdict *private,char *key,int val) {
   char buf[20];

   if (val==0)
      return;
   sprintf(buf, "%d", val);
   privateadd(private, key, fastrdup(buf));
}

static void privateaddintarray(struct psdict *private,char *key,int val) {
   char buf[20];

   if (val==0)
      return;
   sprintf(buf, "[%d]", val);
   privateadd(private, key, fastrdup(buf));
}

static void privateaddreal(struct psdict *private,char *key,double val,
			   double def) {
   char buf[40];

   if (val==def)
      return;
   sprintf(buf, "%g", val);
   privateadd(private, key, fastrdup(buf));
}

static void cffprivatefillup(struct psdict *private,struct topdicts *dict) {
   private->cnt=14;
   private->keys=malloc(14*sizeof(char *));
   private->values=malloc(14*sizeof(char *));
   privateadd(private, "BlueValues",
	      realarray2str(dict->bluevalues,
			    sizeof(dict->bluevalues) /
			    sizeof(dict->bluevalues[0]), true));
   privateadd(private, "OtherBlues",
	      realarray2str(dict->otherblues,
			    sizeof(dict->otherblues) /
			    sizeof(dict->otherblues[0]), true));
   privateadd(private, "FamilyBlues",
	      realarray2str(dict->familyblues,
			    sizeof(dict->familyblues) /
			    sizeof(dict->familyblues[0]), true));
   privateadd(private, "FamilyOtherBlues",
	      realarray2str(dict->familyotherblues,
			    sizeof(dict->familyotherblues) /
			    sizeof(dict->familyotherblues[0]), true));
   privateaddreal(private, "BlueScale", dict->bluescale, 0.039625);
   privateaddreal(private, "BlueShift", dict->blueshift, 7);
   privateaddreal(private, "BlueFuzz", dict->bluefuzz, 1);
   privateaddintarray(private, "StdHW", dict->stdhw);
   privateaddintarray(private, "StdVW", dict->stdvw);
   privateadd(private, "StemSnapH",
	      realarray2str(dict->stemsnaph,
			    sizeof(dict->stemsnaph) /
			    sizeof(dict->stemsnaph[0]), false));
   privateadd(private, "StemSnapV",
	      realarray2str(dict->stemsnapv,
			    sizeof(dict->stemsnapv) /
			    sizeof(dict->stemsnapv[0]), false));
   if (dict->forcebold)
      privateadd(private, "ForceBold", fastrdup("true"));
   if (dict->forceboldthreshold != 0)
      privateaddreal(private, "ForceBoldThreshold", dict->forceboldthreshold,
		     0);
   privateaddint(private, "LanguageGroup", dict->languagegroup);
   privateaddreal(private, "ExpansionFactor", dict->expansionfactor, 0.06);
}

static SplineFont *cffsffillup(struct topdicts *subdict,char **strings,
			       int scnt, struct ttfinfo *info) {
   SplineFont *sf=SplineFontEmpty();
   int emsize;
   static int nameless;

   sf->fontname =
      utf8_verify_copy(getsid(subdict->sid_fontname, strings, scnt, info));
   if (sf->fontname==NULL) {
      char buffer[40];

      sprintf(buffer, "UntitledSubFont_%d", ++nameless);
      sf->fontname=fastrdup(buffer);
   }

   if (subdict->fontmatrix[0]==0)
      emsize=1000;
   else
      emsize=rint(1/subdict->fontmatrix[0]);
   sf->ascent=.8*emsize;
   sf->descent=emsize-sf->ascent;
   if (subdict->copyright != -1)
      sf->copyright =
	 utf8_verify_copy(getsid(subdict->copyright, strings, scnt, info));
   else
      sf->copyright =
	 utf8_verify_copy(getsid(subdict->notice, strings, scnt, info));
   sf->familyname =
      utf8_verify_copy(getsid(subdict->familyname, strings, scnt, info));
   sf->fullname =
      utf8_verify_copy(getsid(subdict->fullname, strings, scnt, info));
   sf->weight =
      utf8_verify_copy(getsid(subdict->weight, strings, scnt, info));
   sf->version =
      utf8_verify_copy(getsid(subdict->version, strings, scnt, info));
   sf->italicangle=subdict->italicangle;
   sf->upos=subdict->underlinepos;
   sf->uwidth=subdict->underlinewidth;
   sf->xuid =
      intarray2str(subdict->xuid,
		   sizeof(subdict->xuid)/sizeof(subdict->xuid[0]));
   sf->uniqueid=subdict->uniqueid;
   sf->strokewidth=subdict->strokewidth;
   sf->strokedfont=subdict->painttype==2;

   if (subdict->private_size>0) {
      sf->private=calloc(1, sizeof(struct psdict));
      cffprivatefillup(sf->private, subdict);
   }
   return (sf);
}

static void cffinfofillup(struct ttfinfo *info,struct topdicts *dict,
			  char **strings, int scnt) {

   info->glyph_cnt=dict->glyphs.cnt;
   if (info->glyph_cnt<0)
      info->glyph_cnt=0;

   if (dict->fontmatrix[0]==0)
      info->emsize=1000;
   else
      info->emsize=rint(1/dict->fontmatrix[0]);
   info->ascent=.8*info->emsize;
   info->descent=info->emsize-info->ascent;
   if (dict->copyright != -1 || dict->notice != -1)
      free(info->copyright);
   if (dict->copyright != -1)
      info->copyright =
	 utf8_verify_copy(getsid(dict->copyright, strings, scnt, info));
   else if (dict->notice != -1)
      info->copyright =
	 utf8_verify_copy(getsid(dict->notice, strings, scnt, info));
   if (dict->familyname != -1) {
      free(info->familyname);
      info->familyname =
	 utf8_verify_copy(getsid(dict->familyname, strings, scnt, info));
   }
   if (dict->fullname != -1) {
      free(info->fullname);
      info->fullname =
	 utf8_verify_copy(getsid(dict->fullname, strings, scnt, info));
   }
   if (dict->weight != -1) {
      free(info->weight);
      info->weight =
	 utf8_verify_copy(getsid(dict->weight, strings, scnt, info));
   }
   if (dict->version != -1) {
      free(info->version);
      info->version =
	 utf8_verify_copy(getsid(dict->version, strings, scnt, info));
   }
   if (dict->fontname != NULL) {
      free(info->fontname);
      info->fontname=utf8_verify_copy(dict->fontname);
   }
   info->italicAngle=dict->italicangle;
   info->upos=dict->underlinepos;
   info->uwidth=dict->underlinewidth;
   info->xuid =
      intarray2str(dict->xuid, sizeof(dict->xuid)/sizeof(dict->xuid[0]));
   info->uniqueid=dict->uniqueid;
   info->strokewidth=dict->strokewidth;
   info->strokedfont=dict->painttype==2;

   if (dict->private_size>0) {
      info->private=calloc(1, sizeof(struct psdict));
      cffprivatefillup(info->private, dict);
   }
   if (dict->ros_registry != -1) {
      info->cidregistry =
	 fastrdup(getsid(dict->ros_registry, strings, scnt, info));
      info->ordering=fastrdup(getsid(dict->ros_ordering, strings, scnt, info));
      info->supplement=dict->ros_supplement;
      info->cidfontversion=dict->cidfontversion;
   }
}

static void cfffigure(struct ttfinfo *info,struct topdicts *dict,
		      char **strings, int scnt, struct pschars *gsubrs) {
   int i, cstype;
   struct pschars *subrs;
   struct pscontext pscontext;

   memset(&pscontext, 0, sizeof(pscontext));

   cffinfofillup(info, dict, strings, scnt);

/* The format allows for some dicts that are type1 strings and others that */
/*  are type2s. Which means that the global subrs will have a different bias */
/*  as we flip from font to font. So we can't set the bias when we read in */
/*  the subrs but must wait until we know which font we're working on. */
   cstype=dict->charstringtype;
   pscontext.is_type2=cstype-1;
   pscontext.painttype=dict->painttype;
   gsubrs->bias=cstype==1?0 :
      gsubrs->cnt<1240?107:gsubrs->cnt<33900?1131:32768;
   subrs=&dict->local_subrs;
   subrs->bias=cstype==1?0 :
      subrs->cnt<1240?107:subrs->cnt<33900?1131:32768;

   info->chars=calloc(info->glyph_cnt, sizeof(SplineChar *));
   for (i=0; i<info->glyph_cnt; ++i) {
      info->chars[i] =
	 PSCharStringToSplines(dict->glyphs.values[i], dict->glyphs.lens[i],
			       &pscontext, subrs, gsubrs,
			       getsid(dict->charset[i], strings, scnt, info));
      info->chars[i]->vwidth=info->emsize;
      if (cstype==2) {
	 if (info->chars[i]->width==(int16_t) 0x8000)
	    info->chars[i]->width=dict->defaultwidthx;
	 else
	    info->chars[i]->width += dict->nominalwidthx;
      }
   }
   /* Need to do a reference fixup here !!!!! just in case some idiot */
   /*  used type1 char strings -- or used the depreciated meaning of */
   /*  endchar (==seac) */
}

static void cidfigure(struct ttfinfo *info,struct topdicts *dict,
		      char **strings, int scnt, struct pschars *gsubrs,
		      struct topdicts **subdicts, uint8_t * fdselect) {
   int i, j, cstype, uni, cid;
   struct pschars *subrs;
   SplineFont *sf;
   struct cidmap *map;
   char buffer[100];
   struct pscontext pscontext;
   EncMap *encmap=NULL;

   memset(&pscontext, 0, sizeof(pscontext));

   cffinfofillup(info, dict, strings, scnt);

   /* We'll set the encmap later */
   /*info->map=encmap=EncMapNew(info->glyph_cnt,info->glyph_cnt,&custom); */

   for (j=0; subdicts[j] != NULL; ++j);
   info->subfontcnt=j;
   info->subfonts=calloc(j+1, sizeof(SplineFont *));
   for (j=0; subdicts[j] != NULL; ++j) {
      info->subfonts[j]=cffsffillup(subdicts[j], strings, scnt, info);
      info->subfonts[j]->map=encmap;
   }
   for (i=0; i<info->glyph_cnt; ++i) {
      sf=info->subfonts[fdselect[i]];
      cid=dict->charset[i];
      if (cid >= sf->glyphcnt)
	 sf->glyphcnt=sf->glyphmax=cid+1;
      /*if (cid>=encmap->enccount ) encmap->enccount=cid+1; */
   }
   for (j=0; subdicts[j] != NULL; ++j)
      info->subfonts[j]->glyphs =
	 calloc(info->subfonts[j]->glyphcnt, sizeof(SplineChar *));
   /*encmap->encmax=encmap->enccount; */
   /*encmap->map=malloc(encmap->enccount*sizeof(int)); */
   /*memset(encmap->map,-1,encmap->enccount*sizeof(int)); */

   info->chars=calloc(info->glyph_cnt, sizeof(SplineChar *));

   /* info->chars provides access to the chars ordered by glyph, which the */
   /*  ttf routines care about */
   /* sf->glyphs provides access to the chars ordered by CID. Not sure what */
   /*  would happen to a kern from one font to another... */

   map =
      FindCidMap(info->cidregistry, info->ordering, info->supplement, NULL);

   for (i=0; i<info->glyph_cnt; ++i) {
      j=fdselect[i];
      sf=info->subfonts[j];
/* The format allows for some dicts that are type1 strings and others that */
/*  are type2s. Which means that the global subrs will have a different bias */
/*  as we flip from font to font. So we can't set the bias when we read in */
/*  the subrs but must wait until we know which font we're working on. */
      cstype=subdicts[j]->charstringtype;
      pscontext.is_type2=cstype-1;
      pscontext.painttype=subdicts[j]->painttype;
      gsubrs->bias=cstype==1?0 :
	 gsubrs->cnt<1240?107:gsubrs->cnt<33900?1131:32768;
      subrs=&subdicts[j]->local_subrs;
      subrs->bias=cstype==1?0 :
	 subrs->cnt<1240?107:subrs->cnt<33900?1131:32768;

      cid=dict->charset[i];
      /*encmap->map[cid]=cid; */
      uni=CID2NameUni(map, cid, buffer, sizeof(buffer));
      info->chars[i] =
	 PSCharStringToSplines(dict->glyphs.values[i], dict->glyphs.lens[i],
			       &pscontext, subrs, gsubrs, buffer);
      info->chars[i]->vwidth=sf->ascent+sf->descent;
      info->chars[i]->unicodeenc=uni;
      info->chars[i]->altuni=CIDSetAltUnis(map, cid);
      sf->glyphs[cid]=info->chars[i];
      sf->glyphs[cid]->parent=sf;
      sf->glyphs[cid]->orig_pos=cid;	/* Bug! should be i, but I assume sf->chars[orig_pos]->orig_pos==orig_pos */
      if (sf->glyphs[cid]->layers[ly_fore].refs != NULL)
	 ErrorMsg(2,"Reference found in CID font. Can't fix it up\n");
      if (cstype==2) {
	 if (sf->glyphs[cid]->width==(int16_t) 0x8000)
	    sf->glyphs[cid]->width=subdicts[j]->defaultwidthx;
	 else
	    sf->glyphs[cid]->width += subdicts[j]->nominalwidthx;
      }
   }
   /* No need to do a reference fixup here-- the chars aren't associated */
   /*  with any encoding as is required for seac */
}

static int readcffglyphs(AFILE *ttf,struct ttfinfo *info) {
   int offsize;
   int hdrsize;
   char **fontnames, **strings;
   struct topdicts **dicts, **subdicts;
   int i, j, which;
   struct pschars gsubs;
   uint8_t *fdselect;
   int scnt;

   afseek(ttf, info->cff_start, SEEK_SET);
   if (agetc(ttf) != '\1') {	/* Major version */
      ErrorMsg(2,"CFF version mismatch\n");
      info->bad_cff=true;
      return (0);
   }
   agetc(ttf);			/* Minor version */
   hdrsize=agetc(ttf);
   offsize=agetc(ttf);
   if (hdrsize != 4)
      afseek(ttf, info->cff_start+hdrsize, SEEK_SET);
   fontnames=readcfffontnames(ttf, NULL, info);
   which=0;
   if (fontnames[1] != NULL) {	/* More than one? Can that even happen in OpenType? */
      which=PickCFFFont(fontnames);
      if (which==-1) {
	 for (i=0; fontnames[i] != NULL; ++i)
	    free(fontnames[i]);
	 free(fontnames);
	 return (0);
      }
   }
   dicts=readcfftopdicts(ttf, fontnames, info->cff_start, info, NULL);
   /* String index is just the same as fontname index */
   strings=readcfffontnames(ttf, &scnt, info);
   readcffsubrs(ttf, &gsubs, info);
   /* Can be many fonts here. Only decompose the one */
   if (dicts[which]->charstringsoff != -1) {
      afseek(ttf, info->cff_start+dicts[which]->charstringsoff, SEEK_SET);
      readcffsubrs(ttf, &dicts[which]->glyphs, info);
   }
   if (dicts[which]->private_offset != -1)
      readcffprivate(ttf, dicts[which], info);
   if (dicts[which]->charsetoff != -1)
      readcffset(ttf, dicts[which], info);
   if (dicts[which]->fdarrayoff==-1)
      cfffigure(info, dicts[which], strings, scnt, &gsubs);
   else {
      afseek(ttf, info->cff_start+dicts[which]->fdarrayoff, SEEK_SET);
      subdicts =
	 readcfftopdicts(ttf, NULL, info->cff_start, info, dicts[which]);
      afseek(ttf, info->cff_start+dicts[which]->fdselectoff, SEEK_SET);
      fdselect=readfdselect(ttf, dicts[which]->glyphs.cnt, info);
      for (j=0; subdicts[j] != NULL; ++j) {
	 if (subdicts[j]->private_offset != -1)
	    readcffprivate(ttf, subdicts[j], info);
	 if (subdicts[j]->charsetoff != -1)
	    readcffset(ttf, subdicts[j], info);
      }
      cidfigure(info, dicts[which], strings, scnt, &gsubs, subdicts,
		fdselect);
      for (j=0; subdicts[j] != NULL; ++j)
	 TopDictFree(subdicts[j]);
      free(subdicts);
      free(fdselect);
   }
   if (dicts[which]->encodingoff != -1)
      readcffenc(ttf, dicts[which], info, strings, scnt);

   if (dicts[which]->fdarrayoff==-1) {
      for (i=0; i<info->glyph_cnt; ++i)
	 if (info->chars[i] != NULL)
	    info->chars[i]->orig_pos=i;
   }

   if (info->to_order2) {
      for (i=0; i<info->glyph_cnt; ++i)
	 SCConvertToOrder2(info->chars[i]);
   }

   for (i=0; fontnames[i] != NULL && i<1; ++i) {
      free(fontnames[i]);
      TopDictFree(dicts[i]);
   }
   free(fontnames);
   free(dicts);
   if (strings != NULL) {
      for (i=0; strings[i] != NULL; ++i)
	 free(strings[i]);
      free(strings);
   }
   for (i=0; i<gsubs.cnt; ++i)
      free(gsubs.values[i]);
   free(gsubs.values);
   free(gsubs.lens);

   return (1);
}

static int readtyp1glyphs(AFILE *ttf,struct ttfinfo *info) {
   FontDict *fd;
   AFILE *tmp;
   int i;
   SplineChar *sc;

   afseek(ttf, info->typ1_start, SEEK_SET);
/* There appear to be about 20 bytes of garbage (well, I don't know what they */
/*  mean, so they are garbage to me) before the start of the PostScript. But */
/*  it's not exactly 20. I've seen 22 and 24. So see if we can find "%!PS-Adobe" */
/*  in the first few bytes of the file, and skip to there if found */
   {
      char buffer[41];

      afread(buffer, 1, sizeof(buffer), ttf);
      buffer[40]='\0';
      for (i=39; i >= 0; --i)
	 if (buffer[i]=='%' && buffer[i+1]=='!')
	    break;
      if (i<0)
	 i=0;
      afseek(ttf, info->typ1_start+i, SEEK_SET);
   }

   tmp=atmpfile();
   for (i=0; i<info->typ1_length; ++i)
      aputc(agetc(ttf), tmp);
   afseek(tmp,0,SEEK_SET);
   fd=_ReadPSFont(tmp);
   afclose(tmp);
   if (fd != NULL) {
      SplineFont *sf=SplineFontFromPSFont(fd);

      PSFontFree(fd);
      info->emsize=(sf->ascent+sf->descent);
      info->ascent=sf->ascent;
      info->descent=sf->descent;
      if (sf->subfontcnt != 0) {
	 info->subfontcnt=sf->subfontcnt;
	 info->subfonts=sf->subfonts;
	 info->cidregistry=fastrdup(sf->cidregistry);
	 info->ordering=fastrdup(sf->ordering);
	 info->supplement=sf->supplement;
	 info->cidfontversion=sf->cidversion;
	 sf->subfonts=NULL;
	 sf->subfontcnt=0;
      } else {
	 info->chars=sf->glyphs;
	 info->glyph_cnt=sf->glyphcnt;
	 for (i=sf->glyphcnt-1; i >= 0; --i)
	    if ((sc=sf->glyphs[i]) != NULL)
	       sc->parent=NULL;
	 sf->glyphs=NULL;
	 sf->glyphcnt=0;
      }
      SplineFontFree(sf);
      return (true);
   }
   return (false);
}

static void readttfwidths(AFILE *ttf,struct ttfinfo *info) {
   int i, j;
   int lastwidth=info->emsize, lsb;

   /* I'm not interested in the lsb, I'm not sure what it means if it differs */
   /*  from that is specified in the outline. Do we move the outline? */
   /* Ah... I am interested in it if bit 1 of 'head'.flags is set, then we */
   /*  do move the outline */
   int check_width_consistency=info->cff_start != 0
      && info->glyph_start==0;
   SplineChar *sc;
   double trans[6];

   memset(trans, 0, sizeof(trans));
   trans[0]=trans[3]=1;

   afseek(ttf, info->hmetrics_start, SEEK_SET);
   for (i=0; i<info->width_cnt && i<info->glyph_cnt; ++i) {
      lastwidth=aget_uint16_be(ttf);
      lsb=(short) aget_uint16_be(ttf);
      if ((sc=info->chars[i]) != NULL) {	/* can happen in ttc files */
	 if (lastwidth>info->advanceWidthMax && info->hhea_start != 0) {
	    if (!info->wdthcomplain || (info->openflags&of_fontlint)) {
	       if (info->fontname != NULL && sc->name != NULL)
		  ErrorMsg(2,"In %s, the advance width (%d) for glyph %s is greater than the maximum (%d)\n",
			   info->fontname, lastwidth, sc->name,
			   info->advanceWidthMax);
	       else
		  ErrorMsg(2,"In GID %d the advance width (%d) is greater than the stated maximum (%d)\n",
			   i, lastwidth, info->advanceWidthMax);
	       if (!(info->openflags&of_fontlint))
		  ErrorMsg(2,"  Subsequent errors will not be reported.\n");
	       info->wdthcomplain=true;
	    }
	 }
	 if (check_width_consistency && sc->width != lastwidth) {
	    if (info->fontname != NULL && sc->name != NULL)
	       ErrorMsg(2,"In %s, in glyph %s, 'CFF ' advance width (%d) and\n  'hmtx' width (%d) do not match. (Subsequent mismatches will not be reported)\n",
			info->fontname, sc->name, sc->width, lastwidth);
	    else
	       ErrorMsg(2,"In GID %d, 'CFF ' advance width (%d) and 'hmtx' width (%d) do not match.\n  (Subsequent mismatches will not be reported)\n",
			i, sc->width, lastwidth);
	    info->bad_metrics=true;
	    check_width_consistency=false;
	 }
	 sc->width=lastwidth;
	 sc->widthset=true;
	 if (info->apply_lsb) {
	    if (sc->lsidebearing != lsb) {
	       trans[4]=lsb-sc->lsidebearing;
	       SplinePointListTransform(sc->layers[ly_fore].splines, trans,
					tpt_AllPoints);
	    }
	 }
      }
   }
   if (i==0) {
      ErrorMsg(2,"Invalid ttf hmtx table (or hhea), numOfLongMetrics is 0\n");
      info->bad_metrics=true;
   }

   for (j=i; j<info->glyph_cnt; ++j) {
      if ((sc=info->chars[j]) != NULL) {	/* In a ttc file we may skip some */
	 sc->width=lastwidth;
	 sc->widthset=true;
	 if (info->apply_lsb) {
	    lsb=(short) aget_uint16_be(ttf);
	    if (sc->lsidebearing != lsb) {
	       trans[4]=lsb-sc->lsidebearing;
	       SplinePointListTransform(sc->layers[ly_fore].splines, trans,
					tpt_AllPoints);
	    }
	 }
      }
   }
}

static void dummywidthsfromstrike(AFILE *ttf,struct ttfinfo *info) {
   BDFFont *bdf;
   int i, cnt;
   double scaled_sum;

   if (info->bitmaps==NULL)
      return;
   for (i=0; i<info->glyph_cnt; ++i)
      if (info->chars[i] != NULL) {
	 cnt=0;
	 scaled_sum=0;
	 for (bdf=info->bitmaps; bdf->next != NULL; bdf=bdf->next) {
	    if (i<bdf->glyphcnt && bdf->glyphs[i] != NULL) {
	       scaled_sum +=
		  ((double) (info->emsize * bdf->glyphs[i]->width)) /
		  bdf->pixelsize;
	       ++cnt;
	    }
	 }
	 if (cnt != 0) {
	    info->chars[i]->width=scaled_sum/cnt;
	    info->chars[i]->widthset=true;
	 }
      }
}

static void readttfvwidths(AFILE *ttf,struct ttfinfo *info) {
   int i, j;
   int lastvwidth=info->emsize, vwidth_cnt, tsb /*, cnt=0 */ ;

   /* int32_t voff=0; */

   afseek(ttf, info->vhea_start+4+4, SEEK_SET);	/* skip over the version number&typo right/left */
   info->pfminfo.vlinegap=aget_uint16_be(ttf);
   info->pfminfo.vheadset=true;

   for (i=0; i<12; ++i)
      aget_uint16_be(ttf);
   vwidth_cnt=aget_uint16_be(ttf);

   afseek(ttf, info->vmetrics_start, SEEK_SET);
   for (i=0; i<vwidth_cnt && i<info->glyph_cnt; ++i) {
      lastvwidth=aget_uint16_be(ttf);
      tsb=aget_uint16_be(ttf);
      if (info->chars[i] != NULL)	/* can happen in ttc files */
	 info->chars[i]->vwidth=lastvwidth;
   }
   if (i==0) {
      ErrorMsg(2,"Invalid ttf vmtx table (or vhea), numOfLongVerMetrics is 0\n");
      info->bad_metrics=true;
   }

   for (j=i; j<info->glyph_cnt; ++j) {
      if (info->chars[j] != NULL)	/* In a ttc file we may skip some */
	 info->chars[j]->vwidth=lastvwidth;
   }

}

static int badencoding(struct ttfinfo *info) {
   if (!info->bad_cmap) {
      ErrorMsg(2,"Bad encoding information in 'cmap' table.\n");
      info->bad_cmap=true;
   }
   return (-1);
}

static int umodenc(int enc,int modtype,struct ttfinfo *info) {
   if (modtype==-1)
      return (-1);
   if (modtype <= 1 /* Unicode */ ) {
      /* No conversion needed, already unicode */ ;
   } else if (modtype==2 /* SJIS */ ) {
      /* FIXME look up directly instead of hardcoding the translations here */
      if (enc <= 127) {
	 /* Latin */
	 if (enc=='\\')
	    enc=0xa5;		/* Yen */
      } else if (enc >= 161 && enc <= 223) {
	 /* Katakana */
	 enc=enc_jis0201_lookup(enc);
      } else if (enc<255) {
	 /* This is erroneous as I understand SJIS */
	 enc=badencoding(info);
      } else {
	 int ch1=enc >> 8, ch2=enc&0xff;

	 if (ch1 >= 129 && ch1 <= 159)
	    ch1 -= 112;
	 else
	    ch1 -= 176;
	 ch1 <<= 1;
	 if (ch2 >= 159)
	    ch2 -= 126;
	 else if (ch2>127) {
	    --ch1;
	    ch2 -= 32;
	 } else {
	    --ch1;
	    ch2 -= 31;
	 }
	 if (ch1<0x21 || ch2<0x21 || ch1>0x7f || ch2>0x7f)
	    enc=badencoding(info);
	 else
	    enc=enc_jis0208_lookup((ch1<<8)+ch2);
      }
   } else if (modtype ==
	      3 /* GB2312 offset by 0x8080, parse just like wansung */ ) {
      enc=enc_gb2312_lookup(enc);
   } else if (modtype==4 /* BIG5 */ ) {	/* old ms docs say big5 is modtype==3, but new ones say 4 */
      enc=enc_big5hkscs_lookup(enc);
   } else if (modtype==5 /* Wansung==KSC 5601-1987, I hope */ ) {
      enc=enc_ksc5601_lookup(enc);
   } else if (modtype==6 /* Johab */ ) {
      if (enc>0x8400)
	 enc=enc_johab_lookup(enc);
      else if (enc>0x100)
	 enc=badencoding(info);
   }
   if (enc==0)
      enc=-1;
   return (enc);
}

struct cmap_encs {
   int platform;
   int specific;
   int offset;
   int lang;
   int format;
   Encoding *enc;
};

static int SubtableIsntSupported(AFILE *ttf,uint32_t offset,
				 struct cmap_encs *cmap_enc,
				 struct ttfinfo *info) {
   uint32_t here=aftell(ttf);
   int format, len, ret=false;

   afseek(ttf, offset, SEEK_SET);

   cmap_enc->format=format=aget_uint16_be(ttf);
   if (format<0 || (format&1) || format>12) {
      ErrorMsg(2,"Encoding subtable for platform=%d, specific=%d has an unsupported format %d.\n",
	       cmap_enc->platform, cmap_enc->specific, format);
      info->bad_cmap=true;
      ret=true;
   }

   if (format != 12 && format != 10 && format != 8) {
      len=aget_uint16_be(ttf);
      cmap_enc->lang=aget_uint16_be(ttf);
   } else {
      /* padding */ aget_uint16_be(ttf);
      len=aget_int32_be(ttf);
      cmap_enc->lang=aget_int32_be(ttf);
   }
   if (len==0) {
      ErrorMsg(2,"Encoding subtable for platform=%d, specific=%d has a 0 length subtable.\n",
	       cmap_enc->platform, cmap_enc->specific);
      info->bad_cmap=true;
      ret=true;
   }
   afseek(ttf, here, SEEK_SET);
   return (ret);
}

static int SubtableMustBe14(AFILE *ttf,uint32_t offset,struct ttfinfo *info) {
   uint32_t here=aftell(ttf);
   int format, ret=true;

   afseek(ttf, offset, SEEK_SET);

   format=aget_uint16_be(ttf);
   if (format != 14) {
      ErrorMsg(2,"Encoding subtable for platform=%d, specific=%d (which must be 14)\nhas an unsupported format %d.\n",
	       0, 5, format);
      info->bad_cmap=true;
      ret=false;
   }
   afseek(ttf, here, SEEK_SET);
   return (ret);
}

static void ApplyVariationSequenceSubtable(AFILE *ttf,uint32_t vs_map,
					   struct ttfinfo *info,
					   int justinuse) {
   int sub_table_len, vs_cnt, i, j, rcnt, gid, cur_gid;
   struct vs_data {
      int vs;
      uint32_t def, non_def;
   } *vs_data;
   SplineChar *sc;

   afseek(ttf, vs_map, SEEK_SET);
   /* We/ve already checked the format is 14 */ aget_uint16_be(ttf);
   sub_table_len=aget_int32_be(ttf);
   vs_cnt=aget_int32_be(ttf);
   vs_data=malloc(vs_cnt * sizeof(struct vs_data));
   for (i=0; i<vs_cnt; ++i) {
      vs_data[i].vs=aget_uint24_be(ttf);
      vs_data[i].def=aget_int32_be(ttf);
      vs_data[i].non_def=aget_int32_be(ttf);
   }

   for (i=0; i<vs_cnt; ++i) {
      if (vs_data[i].def != 0 && justinuse==git_normal) {
	 afseek(ttf, vs_map+vs_data[i].def, SEEK_SET);
	 rcnt=aget_int32_be(ttf);
	 for (j=0; j<rcnt; ++j) {
	    int start_uni=aget_uint24_be(ttf);
	    int cnt=agetc(ttf);
	    int uni;

	    for (uni=start_uni; uni <= start_uni+cnt; ++uni) {
	       SplineChar *sc;
	       struct altuni *altuni;

	       for (gid=0; gid<info->glyph_cnt; ++gid) {
		  if ((sc=info->chars[gid]) != NULL) {
		     if (sc->unicodeenc==uni)
			break;
		     for (altuni=sc->altuni; altuni != NULL;
			  altuni=altuni->next)
			if (altuni->unienc==uni && altuni->vs==-1
			    && altuni->fid==0)
			   break;
		     if (altuni != NULL)
			break;
		  }
	       }
	       if (gid==info->glyph_cnt) {
		  ErrorMsg(2,"No glyph with unicode U+%05x in font\n", uni);
		  info->bad_cmap=true;
	       } else {
		  altuni=chunkalloc(sizeof(struct altuni));
		  altuni->unienc=uni;
		  altuni->vs=vs_data[i].vs;
		  altuni->fid=0;
		  altuni->next=sc->altuni;
		  sc->altuni=altuni;
	       }
	    }
	 }
      }
      if (vs_data[i].non_def != 0) {
	 afseek(ttf, vs_map+vs_data[i].non_def, SEEK_SET);
	 rcnt=aget_int32_be(ttf);
	 for (j=0; j<rcnt; ++j) {
	    int uni=aget_uint24_be(ttf);
	    int curgid=aget_uint16_be(ttf);

	    if (justinuse==git_justinuse) {
	       if (curgid<info->glyph_cnt && curgid >= 0)
		  info->inuse[curgid]=1;
	    } else if (justinuse==git_justinuse) {
	       if (curgid<info->glyph_cnt && curgid >= 0 &&
		   (sc=info->chars[curgid]) != NULL && sc->name==NULL) {
		  char buffer[32];

		  sprintf(buffer, "u%04X.vs%04X", uni, vs_data[i].vs);
		  sc->name=fastrdup(buffer);
	       }
	    } else {
	       if (curgid >= info->glyph_cnt || curgid<0 ||
		   info->chars[curgid]==NULL) {
		  ErrorMsg(2,"GID out of range (%d) in format 14 'cmap' subtable\n",
			   cur_gid);
		  info->bad_cmap=true;
	       } else {
		  SplineChar *sc=info->chars[curgid];
		  struct altuni *altuni=chunkalloc(sizeof(struct altuni));

		  altuni->unienc=uni;
		  altuni->vs=vs_data[i].vs;
		  altuni->fid=0;
		  altuni->next=sc->altuni;
		  sc->altuni=altuni;
	       }
	    }
	 }
      }
   }
   free(vs_data);
}

static enum uni_interp amscheck(struct ttfinfo *info,EncMap *map) {
   int cnt=0;

   /* Try to guess if the font uses the AMS math PUA assignments */

   if (map==NULL)
      return (ui_none);

   if (0xe668<map->enccount && map->map[0xe668] != -1 &&
       info->chars[map->map[0xe668]]->unicodeenc=='b')
      ++cnt;
   if (0xe3c8<map->enccount && map->map[0xe626] != -1 &&
       info->chars[map->map[0xe626]]->unicodeenc==0xe626)
      ++cnt;
   if (0xe3c8<map->enccount && map->map[0xe3c8] != -1 &&
       info->chars[map->map[0xe3c8]]->unicodeenc==0x29e1)
      ++cnt;
   if (0x2A7C<map->enccount && map->map[0x2A7C] != -1 &&
       info->chars[map->map[0x2A7C]]->unicodeenc==0xE32A)
      ++cnt;
   if (0x2920<map->enccount && map->map[0x2920] != -1 &&
       info->chars[map->map[0x2920]]->unicodeenc==0xE221)
      ++cnt;
   return (cnt >= 2?ui_ams:ui_none);
}

static int PickCMap(struct cmap_encs *cmap_encs,int enccnt,int def) {
   char buffer[500];
   char **choices, *encname;
   int i, ret;
   static char *macscripts[] =
      { "Script|Roman", "Script|Japanese",
"Script|Traditional Chinese", "Script|Korean",
      "Script|Arabic", "Script|Hebrew", "Script|Greek",
/* GT: Don't ask me what RSymbol means, I don't know either. It's in apple's */
/* GT:  docs though */
      "Script|Cyrillic", "Script|RSymbol", "Script|Devanagari",
/* 10*/ "Script|Gurmukhi", "Script|Gujarati", NULL, NULL, NULL,
      NULL, NULL, NULL, NULL, NULL,
/* 20*/ NULL, "Script|Thai", NULL, NULL, NULL,
	 "Script|Simplified Chinese",
      NULL, NULL, NULL, "Script|Central European",
/* 30*/ NULL, NULL, NULL
   };

   choices=malloc(enccnt * sizeof(char *));
   for (i=0; i<enccnt; ++i) {
      encname=NULL;
      if (cmap_encs[i].platform==1 && cmap_encs[i].specific<32) {
	 encname=macscripts[cmap_encs[i].specific];
      } else if (cmap_encs[i].platform==0) {
	 switch (cmap_encs[i].specific) {
	   case 0:
	      encname="Unicode 1.0";
	      break;
	   case 1:
	      encname="Unicode 1.1";
	      break;
	   case 2:
	      encname="ISO 10646:1993";
	      break;
	   case 3:
	      encname="Unicode 2.0+, BMP only";
	      break;
	   case 4:
	      encname="Unicode 2.0+, all planes";
	      break;
	 }
      } else if (cmap_encs[i].platform==3 && cmap_encs[i].specific==0)
	 encname="\"Symbol\"";
      if (encname==NULL)
	 encname=cmap_encs[i].enc->enc_name;

      sprintf(buffer, "%d (%s) %d %s %s  %s",
	      cmap_encs[i].platform,
	      cmap_encs[i].platform==0?"Unicode" :
	      cmap_encs[i].platform==1?"Apple" :
	      cmap_encs[i].platform==2?"ISO (Deprecated)" :
	      cmap_encs[i].platform==3?"MicroSoft" :
	      cmap_encs[i].platform==4?"Custom" :
	      cmap_encs[i].platform==7?"FreeType internals" :
	      "Unknown",
	      cmap_encs[i].specific,
	      encname,
	      cmap_encs[i].platform==1
	      && cmap_encs[i].lang !=
	      0?MacLanguageFromCode(cmap_encs[i].lang-1):"",
	      cmap_encs[i].format ==
	      0?"Byte encoding table":cmap_encs[i].format ==
	      2?"High-byte mapping through table":cmap_encs[i].format ==
	      4?"Segment mapping to delta values":cmap_encs[i].format ==
	      6?"Trimmed table mapping":cmap_encs[i].format ==
	      8?"mixed 16-bit and 32-bit coverage":cmap_encs[i].format ==
	      10?"Trimmed array":cmap_encs[i].format ==
	      12?"Segmented coverage":"Unknown format");
      choices[i]=fastrdup(buffer);
   }
   ret=def;
   for (i=0; i<enccnt; ++i)
      free(choices[i]);
   free(choices);
   return (ret);
}

/* 'cmap' table: readttfcmap */
static void readttfencodings(AFILE *ttf,struct ttfinfo *info,int justinuse) {
   int i, j, def, unicode_cmap, unicode4_cmap, dcnt, dcmap_cnt, dc;
   int nencs, version, usable_encs;
   Encoding *enc=&custom;
   const int32_t *trans=NULL;
   enum uni_interp interp=ui_none;
   int platform, specific;
   int offset, encoff=0;
   int format, len;
   uint32_t vs_map=0;
   uint16_t table[256];
   int segCount;
   uint16_t *endchars, *startchars, *delta, *rangeOffset, *glyphs;
   int index, last;
   int mod=0;
   SplineChar *sc;
   uint8_t *used;
   int badencwarned=false;
   int glyph_tot;
   Encoding *temp;
   EncMap *map;
   struct cmap_encs *cmap_encs, desired_cmaps[2], *dcmap;
   extern int ask_user_for_cmap;

   afseek(ttf, info->encoding_start, SEEK_SET);
   version=aget_uint16_be(ttf);
   nencs=aget_uint16_be(ttf);
   if (version != 0 && nencs==0)
      nencs=version;		/* Sometimes they are backwards */ /* Or was I just confused early on? */
   cmap_encs=malloc(nencs * sizeof(struct cmap_encs));
   for (i=usable_encs=0; i<nencs; ++i) {
      cmap_encs[usable_encs].platform=aget_uint16_be(ttf);
      cmap_encs[usable_encs].specific=aget_uint16_be(ttf);
      cmap_encs[usable_encs].offset=aget_int32_be(ttf);
      if (cmap_encs[usable_encs].platform==0
	  && cmap_encs[usable_encs].specific==5) {
	 /* This isn't a true encoding. */
	 /* It's an optional set of encoding modifications (sort of) */
	 /*  applied to a format 4/10 encoding (unicode BMP/Full) */
	 if (SubtableMustBe14
	     (ttf, info->encoding_start+cmap_encs[usable_encs].offset,
	      info))
	    vs_map=info->encoding_start+cmap_encs[usable_encs].offset;
	 continue;
      }
      temp =
	 enc_from_platspec(cmap_encs[usable_encs].platform,
			   cmap_encs[usable_encs].specific);
      if (temp==NULL)		/* iconv doesn't support this. Some sun iconvs seem limited */
	 temp=FindOrMakeEncoding("Custom");
      cmap_encs[usable_encs].enc=temp;
      if (SubtableIsntSupported
	  (ttf, info->encoding_start+cmap_encs[usable_encs].offset,
	   &cmap_encs[usable_encs], info))
	 continue;
      ++usable_encs;
   }
   if (usable_encs==0) {
      ErrorMsg(2,"Could not find any valid encoding tables\n");
      free(cmap_encs);
      return;
   }
   def=-1;
   enc=&custom;
   unicode_cmap=unicode4_cmap=-1;
   for (i=0; i<usable_encs; ++i) {
      temp=cmap_encs[i].enc;
      platform=cmap_encs[i].platform;
      specific=cmap_encs[i].specific;
      offset=cmap_encs[i].offset;

      if ((platform==3 && specific==10) || (platform==0 && specific==4)) {	/* MS Unicode 4 byte */
	 enc=temp;
	 def=i;
	 unicode4_cmap=i;
      } else if (!enc->is_unicodefull && (!prefer_cjk_encodings || (!enc->is_japanese && !enc->is_korean && !enc->is_tradchinese && !enc->is_simplechinese)) && ((platform==3 && specific==1) ||	/* MS Unicode */
/* Well I should only deal with apple unicode specific==0 (default) and 3 (U2.0 semantics) */
/*  but apple ships dfonts with specific==1 (Unicode 1.1 semantics) */
/*  which is stupid of them */
																				 (platform==0 /*&& (specific==0 || specific==3) */ ))) {	/* Apple Unicode */
	 enc=temp;
	 def=i;
      } else if (platform==3 && specific==0 && enc->is_custom) {
	 /* Only select symbol if we don't have something better */
	 enc=temp;
	 def=i;
	 /* Now I had assumed this would be a 1 byte encoding, but it turns */
	 /*  out to map into the unicode private use area at U+f000-U+F0FF */
	 /*  so it's a 2 byte enc */
/* Mac platform specific encodings are script numbers. 0=>roman, 1=>jap, 2=>big5, 3=>korean, 4=>arab, 5=>hebrew, 6=>greek, 7=>cyrillic, ... 25=>simplified chinese */
      } else if (platform==1 && specific==0 && enc->is_custom) {
	 enc=temp;
	 def=i;
      } else if (platform==1
		 && (specific==2 || specific==1 || specific==3
		     || specific==25) && !enc->is_unicodefull
		 && (prefer_cjk_encodings || !enc->is_unicodebmp)) {
	 enc=temp;
	 def=i;
      } else if (platform==3 && (specific >= 2 && specific <= 6) &&
		 !enc->is_unicodefull &&
		 (prefer_cjk_encodings || !enc->is_unicodebmp)) {
	 /* Old ms docs say that specific==3 => big 5, new docs say specific==4 => big5 */
	 /*  Ain't that jus' great? */
	 enc=temp;
	 def=i;
      }
      if ((platform==3 && specific==1) ||
	  (platform==0 && specific==3))
	 unicode_cmap=i;
   }

   if (justinuse==git_justinuse || !ask_user_for_cmap
       || (i=PickCMap(cmap_encs, usable_encs, def))==-1)
      i=def;

   if (i==-1) {
      if (justinuse==git_normal)
	 ErrorMsg(2,"Could not find a usable encoding table\n");
      free(cmap_encs);
      return;
   }

   info->platform=cmap_encs[i].platform;
   info->specific=cmap_encs[i].specific;

   desired_cmaps[0]=cmap_encs[i];
   dcnt=1;
   if (unicode4_cmap != -1) {
      if (i != unicode4_cmap) {
	 desired_cmaps[1]=cmap_encs[unicode4_cmap];
	 ++dcnt;
      }
   } else if (unicode_cmap != -1) {
      if (i != unicode_cmap) {
	 desired_cmaps[1]=cmap_encs[unicode_cmap];
	 ++dcnt;
      }
   } else {
      if (i != def && def != -1) {
	 desired_cmaps[1]=cmap_encs[def];
	 ++dcnt;
      }
   }

   map=NULL;
   if (justinuse==git_justinuse) {
      dcmap_cnt=usable_encs;
      dcmap=cmap_encs;
   } else {
      dcmap_cnt=dcnt;
      dcmap=desired_cmaps;
   }
   for (dc=dcmap_cnt-1; dc >= 0; --dc) {
      /* if justinuse then look at all cmaps and tick the glyphs they use */
      /* otherwise dcmap_cnt will be either 1 or 2. If 1 then this subtable */
      /* contains both the encoding and the source for unicode encodings */
      /* if dcmap_cnt==2 then when dc==0 we are setting up the encoding */
      /*  and when dc==1 we are setting up the unicode code points */
      int dounicode=(dc==dcmap_cnt-1);

      enc=dcmap[dc].enc;
      encoff=dcmap[dc].offset;

      mod=0;
      if (dcmap[dc].platform==3
	  && (dcmap[dc].specific >= 2 && dcmap[dc].specific <= 6))
	 mod=dcmap[dc].specific;
      else if (dcmap[dc].platform==1
	       && (dcmap[dc].specific==2 || dcmap[dc].specific==1
		   || dcmap[dc].specific==3 || dcmap[dc].specific==25))
	 mod=dcmap[dc].specific==1?2:dcmap[dc].specific==2?4:dcmap[dc].specific==3?5:3;	/* convert to ms specific */
      if (dc==0 && justinuse==git_normal) {
	 interp=interp_from_encoding(enc, ui_none);
	 info->map=map=EncMapNew(enc->char_cnt, info->glyph_cnt, enc);
	 info->uni_interp=interp;
      }

      afseek(ttf, info->encoding_start+encoff, SEEK_SET);
      format=aget_uint16_be(ttf);
      if (format != 12 && format != 10 && format != 8) {
	 len=aget_uint16_be(ttf);
	 /* version/language=*/ aget_uint16_be(ttf);
      } else {
	 /* padding */ aget_uint16_be(ttf);
	 len=aget_int32_be(ttf);
	 /* language=*/ aget_int32_be(ttf);
      }
      if (enc->is_unicodebmp && (format==8 || format==10 || format==12))
	 enc=FindOrMakeEncoding("UnicodeFull");

      if (format==0) {
	 if (justinuse==git_normal && map != NULL && map->enccount<256) {
	    map->map=realloc(map->map, 256*sizeof(int));
	    memset(map->map, -1, (256-map->enccount)*sizeof(int));
	    map->enccount=map->encmax=256;
	 }
	 for (i=0; i<len-6; ++i)
	    table[i]=agetc(ttf);
	 trans=enc->unicode;
	 if (trans==NULL && dcmap[dc].platform==1)
	    trans=MacEncToUnicode(dcmap[dc].specific, dcmap[dc].lang-1);
	 for (i=0; i<256 && i<len-6; ++i)
	    if (justinuse==git_normal) {
	       if (table[i]<info->glyph_cnt
		   && info->chars[table[i]] != NULL) {
		  if (map != NULL)
		     map->map[i]=table[i];
		  if (dounicode && trans != NULL)
		     info->chars[table[i]]->unicodeenc=trans[i];
	       }
	    } else if (table[i]<info->glyph_cnt
		       && info->chars[table[i]] != NULL)
	       info->inuse[table[i]]=1;
      } else if (format==4) {
	 segCount=aget_uint16_be(ttf)/2;
	 /* searchRange=*/ aget_uint16_be(ttf);
	 /* entrySelector=*/ aget_uint16_be(ttf);
	 /* rangeShift=*/ aget_uint16_be(ttf);
	 endchars=malloc(segCount * sizeof(uint16_t));
	 used=calloc(65536, sizeof(uint8_t));
	 for (i=0; i<segCount; ++i)
	    endchars[i]=aget_uint16_be(ttf);
	 if (aget_uint16_be(ttf) != 0)
	    ErrorMsg(2,"Expected 0 in 'cmap' format 4 subtable\n");
	 startchars=malloc(segCount * sizeof(uint16_t));
	 for (i=0; i<segCount; ++i)
	    startchars[i]=aget_uint16_be(ttf);
	 delta=malloc(segCount * sizeof(uint16_t));
	 for (i=0; i<segCount; ++i)
	    delta[i]=aget_uint16_be(ttf);
	 rangeOffset=malloc(segCount * sizeof(uint16_t));
	 for (i=0; i<segCount; ++i)
	    rangeOffset[i]=aget_uint16_be(ttf);
	 len -= 8*sizeof(uint16_t)+4*segCount * sizeof(uint16_t);
	 /* that's the amount of space left in the subtable and it must */
	 /*  be filled with glyphIDs */
	 if (len<0) {
	    ErrorMsg(3,"This font has an illegal format 4 subtable with too little space for all the segments.\n");
	    exit(1);
	 }
	 glyphs=malloc(len);
	 glyph_tot=len/2;
	 for (i=0; i<glyph_tot; ++i)
	    glyphs[i]=aget_uint16_be(ttf);
	 for (i=0; i<segCount; ++i) {
	    if (rangeOffset[i]==0 && startchars[i]==0xffff)
	       /* Done */ ;
	    else if (rangeOffset[i]==0) {
	       for (j=startchars[i]; j <= endchars[i]; ++j) {
		  if (justinuse==git_justinuse
		      && (uint16_t) (j+delta[i])<info->glyph_cnt)
		     info->inuse[(uint16_t) (j+delta[i])]=true;
		  else if ((uint16_t) (j+delta[i]) >= info->glyph_cnt
			   || info->chars[(uint16_t) (j+delta[i])]==NULL) {
		     ErrorMsg(2,"Attempt to encode missing glyph %d to %d (0x%x)\n",
			      (uint16_t)(j+delta[i]),j,j);
		     info->bad_cmap=true;
		  } else {
		     int uenc=umodenc(j, mod, info);
		     int lenc=j;

		     if (uenc != -1 && used[uenc]) {
			if (!badencwarned) {
			   ErrorMsg(2,"Multiple glyphs map to the same unicode encoding U+%04X, only one will be used\n",
				    uenc);
			   info->bad_cmap=true;
			   badencwarned=true;
			}
		     } else {
			if (uenc != -1 && dounicode)
			   used[uenc]=true;
			if (dounicode
			    && info->chars[(uint16_t) (j+delta[i])]->
			    unicodeenc==-1)
			   info->chars[(uint16_t) (j+delta[i])]->unicodeenc =
			      uenc;
			if (map != NULL && lenc<map->enccount)
			   map->map[lenc]=(uint16_t) (j+delta[i]);
		     }
		  }
	       }
	    } else if (rangeOffset[i] != 0xffff) {
	       /* Apple says a rangeOffset of 0xffff means no glyph */
	       /*  OpenType doesn't mention this */
	       for (j=startchars[i]; j <= endchars[i]; ++j) {
		  int temp =
		     (i-segCount+rangeOffset[i]/2)+j-startchars[i];
		  if (temp<glyph_tot)
		     index=glyphs[temp];
		  else {
		     /* This happened in mingliu.ttc(PMingLiU) */
		     if (justinuse==git_normal) {
			ErrorMsg(2,"Glyph index out of bounds. Was %d, must be less than %d.\n In attempt to associate a glyph with encoding %x in segment %d\n with platform=%d, specific=%d (in 'cmap')\n",
				 temp, glyph_tot, j, i, dcmap[dc].platform,
				 dcmap[dc].specific);
			info->bad_cmap=true;
		     }
		     index=0;
		  }
		  if (index != 0) {
		     index=(unsigned short) (index+delta[i]);
		     if (index >= info->glyph_cnt) {
			/* This isn't mentioned either, but in some */
			/*  MS Chinese fonts (kaiu.ttf) the index */
			/*  goes out of bounds. and MS's ttf dump */
			/*  program says it is treated as 0 */
			ErrorMsg(2,"Attempt to encode missing glyph %d to %d (0x%x)\n",
				 index,j,j);
			info->bad_cmap=true;
		     } else if (justinuse==git_justinuse)
			info->inuse[index]=1;
		     else if (info->chars[index]==NULL) {
			ErrorMsg(2,"Attempt to encode missing glyph %d to %d (0x%x)\n",
				 index,j,j);
			info->bad_cmap=true;
		     } else {
			int uenc=umodenc(j,mod,info);
			int lenc=j;

			if (uenc != -1 && used[uenc]) {
			   if (!badencwarned) {
			      ErrorMsg(2,"Multiple glyphs map to the same unicode encoding U+%04X, only one will be used\n",
				       uenc);
			      info->bad_cmap=true;
			      badencwarned=true;
			   }
			} else {
			   if (uenc != -1 && dounicode)
			      used[uenc]=true;
			   if (dounicode
			       && info->chars[index]->unicodeenc==-1)
			      info->chars[index]->unicodeenc=uenc;
			   if (map != NULL && lenc<map->enccount)
			      map->map[lenc]=index;
			}
		     }
		  }
	       }
	    } else {
	       ErrorMsg(2,"Use of a range offset of 0xffff to mean a missing glyph in cmap table\n");
	       info->bad_cmap=true;
	    }
	 }
	 free(glyphs);
	 free(rangeOffset);
	 free(delta);
	 free(startchars);
	 free(endchars);
	 free(used);
      } else if (format==6) {
	 /* trimmed array format */
	 /* Well, the docs say it's for 2byte encodings, but Apple actually */
	 /*  uses it for 1 byte encodings which don't fit into the require- */
	 /*  ments for a format 0 sub-table. See Zapfino.dfont */
	 int first, count;

	 first=aget_uint16_be(ttf);
	 count=aget_uint16_be(ttf);
	 trans=enc->unicode;
	 if (trans==NULL && dcmap[dc].platform==1 && first+count <= 256)
	    trans=MacEncToUnicode(dcmap[dc].specific, dcmap[dc].lang-1);
	 if (justinuse==git_justinuse)
	    for (i=0; i<count; ++i)
	       info->inuse[aget_uint16_be(ttf)]=1;
	 else {
	    for (i=0; i<count; ++i) {
	       int gid=aget_uint16_be(ttf);

	       if (dounicode)
		  info->chars[gid]->unicodeenc =
		     trans != NULL?trans[first+1]:first+i;
	       if (map != NULL && first+i<map->enccount)
		  map->map[first+i]=gid;
	    }
	 }
      } else if (format==2) {
	 int max_sub_head_key=0, cnt, max_pos=-1;
	 struct subhead *subheads;

	 for (i=0; i<256; ++i) {
	    table[i]=aget_uint16_be(ttf)/8;	/* Sub-header keys */
	    if (table[i]>max_sub_head_key) {
	       max_sub_head_key=table[i];	/* The entry is a byte pointer, I want a pointer in units of struct subheader */
	       max_pos=i;
	    }
	 }
	 subheads=malloc((max_sub_head_key+1)*sizeof(struct subhead));
	 for (i=0; i <= max_sub_head_key; ++i) {
	    subheads[i].first=aget_uint16_be(ttf);
	    subheads[i].cnt=aget_uint16_be(ttf);
	    subheads[i].delta=aget_uint16_be(ttf);
	    subheads[i].rangeoff=(aget_uint16_be(ttf) -
				    (max_sub_head_key -
				     i)*sizeof(struct subhead) -
				    sizeof(short))/sizeof(short);
	 }
	 cnt =
	    (len -
	     (aftell(ttf)-(info->encoding_start+encoff)))/sizeof(short);
	 /* The count is the number of glyph indexes to read. it is the */
	 /*  length of the entire subtable minus that bit we've read so far */
	 glyphs=malloc(cnt * sizeof(short));
	 for (i=0; i<cnt; ++i)
	    glyphs[i]=aget_uint16_be(ttf);
	 last=-1;
	 for (i=0; i<256; ++i) {
	    if (table[i]==0) {
	       /* Special case, single byte encoding entry, look it up in */
	       /*  subhead */
	       /* In the one example I've got of this encoding (wcl-02.ttf) the chars */
	       /* 0xfd, 0xfe, 0xff are said to exist but there is no mapping */
	       /* for them. */
	       if (i >= max_pos)
		  index=0;	/* the subhead says there are 256 entries, but in fact there are only 193, so attempting to find these guys should give an error */
	       else if (i<subheads[0].first
			|| i >= subheads[0].first+subheads[0].cnt
			|| subheads[0].rangeoff+(i-subheads[0].first) >=
			cnt)
		  index=0;
	       else
		  if ((index =
		       glyphs[subheads[0].rangeoff +
			      (i-subheads[0].first)]) != 0)
		  index=(uint32_t) (index+subheads[0].delta);
	       /* I assume the single byte codes are just ascii or latin1 */
	       if (index != 0 && index<info->glyph_cnt) {
		  if (justinuse==git_justinuse)
		     info->inuse[index]=1;
		  else if (info->chars[index]==NULL)
		     /* Do Nothing */ ;
		  else {
		     int lenc=i;

		     if (dounicode && info->chars[index]->unicodeenc==-1)
			info->chars[index]->unicodeenc=i;
		     if (map != NULL && lenc<map->enccount)
			map->map[lenc]=index;
		  }
	       }
	    } else {
	       int k=table[i];

	       for (j=0; j<subheads[k].cnt; ++j) {
		  int enc, lenc;

		  if (subheads[k].rangeoff+j >= cnt)
		     index=0;
		  else if ((index=glyphs[subheads[k].rangeoff+j]) != 0)
		     index=(uint16_t) (index+subheads[k].delta);
		  if (index != 0 && index<info->glyph_cnt) {
		     enc=(i << 8)|(j+subheads[k].first);
		     lenc=enc;
		     if (justinuse==git_justinuse)
			info->inuse[index]=1;
		     else if (info->chars[index]==NULL)
			/* Do Nothing */ ;
		     else {
			if (dounicode && info->chars[index]->unicodeenc==-1)
			   info->chars[index]->unicodeenc =
			      umodenc(enc, mod, info);
			if (map != NULL && lenc<map->enccount)
			   map->map[lenc]=index;
		     }
		  }
	       }
	       /*if (last==-1 ) last=i; */
	    }
	 }
	 free(subheads);
	 free(glyphs);
      } else if (format==8) {
	 uint32_t ngroups, start, end, startglyph;

	 if (!enc->is_unicodefull) {
	    ErrorMsg(2,"32-bit characters are not supported except for the UCS-4 (MS platform, specific=10)\n");
	    enc=FindOrMakeEncoding("UnicodeFull");
	 }
	 /* I'm now assuming unicode surrogate encoding, so I just ignore */
	 /*  the is32 table (it will be set for the surrogates and not for */
	 /*  anything else */
	 afseek(ttf, 8192, SEEK_CUR);
	 ngroups=aget_int32_be(ttf);
	 for (j=0; j<ngroups; ++j) {
	    start=aget_int32_be(ttf);
	    end=aget_int32_be(ttf);
	    startglyph=aget_int32_be(ttf);
	    if (justinuse==git_justinuse)
	       for (i=start; i <= end; ++i)
		  info->inuse[startglyph+i-start]=1;
	    else
	       for (i=start; i <= end; ++i) {
		  int uenc =
		     ((i >> 16)-0xd800)*0x400+(i&0xffff)-0xdc00 +
		     0x10000;
		  sc=info->chars[startglyph+i-start];
		  if (dounicode && sc->unicodeenc==-1)
		     sc->unicodeenc=uenc;
		  if (map != NULL && sc->unicodeenc<map->enccount)
		     map->map[uenc]=startglyph+i-start;
	       }
	 }
      } else if (format==10) {
	 /* same as format 6, except for 4byte chars */
	 int first, count;

	 if (!enc->is_unicodefull) {
	    ErrorMsg(2,"32-bit characters are not supported except for the UCS-4 (MS platform, specific=10)\n");
	    enc=FindOrMakeEncoding("UnicodeFull");
	 }
	 first=aget_int32_be(ttf);
	 count=aget_int32_be(ttf);
	 if (justinuse==git_justinuse)
	    for (i=0; i<count; ++i)
	       info->inuse[aget_uint16_be(ttf)]=1;
	 else
	    for (i=0; i<count; ++i) {
	       int gid=aget_uint16_be(ttf);

	       if (dounicode)
		  info->chars[gid]->unicodeenc=first+i;
	       if (map != NULL && first+i<map->enccount)
		  map->map[first+i]=gid;
	    }
      } else if (format==12) {
	 uint32_t ngroups, start, end, startglyph;

	 if (!enc->is_unicodefull) {
	    ErrorMsg(2,"32-bit characters are not supported except for the UCS-4 (MS platform, specific=10)\n");
	    enc=FindOrMakeEncoding("UnicodeFull");
	 }
	 ngroups=aget_int32_be(ttf);
	 for (j=0; j<ngroups; ++j) {
	    start=aget_int32_be(ttf);
	    end=aget_int32_be(ttf);
	    startglyph=aget_int32_be(ttf);
	    if (justinuse==git_justinuse) {
	       for (i=start; i <= end; ++i)
		  if (startglyph+i-start<info->glyph_cnt)
		     info->inuse[startglyph+i-start]=1;
		  else
		     break;
	    } else
	       for (i=start; i <= end; ++i) {
		  if (startglyph+i-start >= info->glyph_cnt ||
		      info->chars[startglyph+i-start]==NULL) {
		     ErrorMsg(2,"Bad font: Encoding data out of range.\n");
		     info->bad_cmap=true;
		     break;
		  } else {
		     if (dounicode)
			info->chars[startglyph+i-start]->unicodeenc=i;
		     if (map != NULL && i<map->enccount)
			map->map[i]=startglyph+i-start;
		  }
	       }
	 }
      }
   }
   free(cmap_encs);
   if (info->chars != NULL)
      for (i=0; i<info->glyph_cnt; ++i)
	 if (info->chars[i] != NULL && info->chars[i]->unicodeenc==0xffff)
	    info->chars[i]->unicodeenc=-1;
   info->vs_start=vs_map;
   if (vs_map != 0)
      ApplyVariationSequenceSubtable(ttf, vs_map, info, justinuse);
   if (justinuse==git_normal) {
      if (interp==ui_none)
	 info->uni_interp=amscheck(info, map);
      map->enc=enc;		/* This can be changed from the initial value */
   }
   info->map=map;
}

static void readttfos2metrics(AFILE *ttf,struct ttfinfo *info) {
   int i, sel;

   afseek(ttf, info->os2_start, SEEK_SET);
   info->os2_version=aget_uint16_be(ttf);
   /* avgWidth */ aget_uint16_be(ttf);
   info->pfminfo.weight=aget_uint16_be(ttf);
   info->pfminfo.width=aget_uint16_be(ttf);
   info->pfminfo.fstype=aget_uint16_be(ttf);
   info->pfminfo.os2_subxsize=aget_uint16_be(ttf);
   info->pfminfo.os2_subysize=aget_uint16_be(ttf);
   info->pfminfo.os2_subxoff=aget_uint16_be(ttf);
   info->pfminfo.os2_subyoff=aget_uint16_be(ttf);
   info->pfminfo.os2_supxsize=aget_uint16_be(ttf);
   info->pfminfo.os2_supysize=aget_uint16_be(ttf);
   info->pfminfo.os2_supxoff=aget_uint16_be(ttf);
   info->pfminfo.os2_supyoff=aget_uint16_be(ttf);
   info->pfminfo.os2_strikeysize=aget_uint16_be(ttf);
   info->pfminfo.os2_strikeypos=aget_uint16_be(ttf);
   info->pfminfo.os2_family_class=aget_uint16_be(ttf);
   for (i=0; i<10; ++i)
      info->pfminfo.panose[i]=agetc(ttf);
   info->pfminfo.pfmfamily=info->pfminfo.panose[0]==2?0x11 :	/* might be 0x21 */ /* Text&Display maps to either serif 0x11 or sans 0x21 or monospace 0x31 */
      info->pfminfo.panose[0]==3?0x41 :	/* Script */
      info->pfminfo.panose[0]==4?0x51 :	/* Decorative */
      0x51;			/* And pictorial doesn't fit into pfm */
   info->pfminfo.unicoderanges[0]=aget_int32_be(ttf);
   info->pfminfo.unicoderanges[1]=aget_int32_be(ttf);
   info->pfminfo.unicoderanges[2]=aget_int32_be(ttf);
   info->pfminfo.unicoderanges[3]=aget_int32_be(ttf);
   info->pfminfo.hasunicoderanges=true;
   info->pfminfo.os2_vendor[0]=agetc(ttf);
   info->pfminfo.os2_vendor[1]=agetc(ttf);
   info->pfminfo.os2_vendor[2]=agetc(ttf);
   info->pfminfo.os2_vendor[3]=agetc(ttf);
   sel=aget_uint16_be(ttf);
   if (info->os2_version >= 4) {
      info->use_typo_metrics=(sel&128)?1:0;
      info->weight_width_slope_only=(sel&256)?1:0;
   }
   /* firstchar */
   aget_uint16_be(ttf);
   /* lastchar */ aget_uint16_be(ttf);
   info->pfminfo.os2_typoascent=aget_uint16_be(ttf);
   info->pfminfo.os2_typodescent=(short) aget_uint16_be(ttf);
   if (info->pfminfo.os2_typoascent-info->pfminfo.os2_typodescent ==
       info->emsize) {
      info->ascent=info->pfminfo.os2_typoascent;
      info->descent=-info->pfminfo.os2_typodescent;
   }
   info->pfminfo.os2_typolinegap=aget_uint16_be(ttf);
   info->pfminfo.os2_winascent=aget_uint16_be(ttf);
   info->pfminfo.os2_windescent=aget_uint16_be(ttf);
   info->pfminfo.winascent_add=info->pfminfo.windescent_add=false;
   info->pfminfo.typoascent_add=info->pfminfo.typodescent_add=false;
   info->pfminfo.pfmset=true;
   info->pfminfo.panose_set=true;
   info->pfminfo.subsuper_set=true;
   if (info->os2_version >= 1) {
      info->pfminfo.codepages[0]=aget_int32_be(ttf);
      info->pfminfo.codepages[1]=aget_int32_be(ttf);
      info->pfminfo.hascodepages=true;
   }

   if (info->os2_version==0) {
      ErrorMsg(2,"Windows will reject fonts with an OS/2 version number of 0\n");
      info->bad_os2_version=true;
   } else if (info->os2_version==1 && info->cff_start != 0) {
      ErrorMsg(2,"Windows will reject otf (cff) fonts with an OS/2 version number of 1\n");
      info->bad_os2_version=true;
   }
}

static void readttfpostnames(AFILE *ttf,struct ttfinfo *info) {
   int i, j;
   int format, len, gc, gcbig, val;
   const char *name;
   char buffer[30];
   uint16_t *indexes;
   extern const char *ttfstandardnames[];
   int notdefwarned=false;
   int anynames=false;

   /* Give ourselves an xuid, just in case they want to convert to PostScript */
   /*  (even type42)                                                         */
   if (xuid != NULL && info->fd==NULL && info->xuid==NULL) {
      info->xuid=malloc(strlen(xuid)+20);
      sprintf(info->xuid,"[%s %d]",xuid,
	      (sfmt_genrand_uint32(&fa_sfmt)&0xffffff));
   }

   if (info->postscript_start != 0) {
      afseek(ttf, info->postscript_start, SEEK_SET);
      format=aget_int32_be(ttf);
      info->italicAngle=(double)aget_int16_be(ttf);
      info->italicAngle+=((double)aget_uint16_be(ttf)/65536.0);
      info->upos=(short) aget_uint16_be(ttf);
      info->uwidth=(short) aget_uint16_be(ttf);
      info->upos += info->uwidth/2;	/* 'post' defn of this field is different from FontInfo defn and I didn't notice */
      info->isFixedPitch=aget_int32_be(ttf);
      /* mem1=*/ aget_int32_be(ttf);
      /* mem2=*/ aget_int32_be(ttf);
      /* mem3=*/ aget_int32_be(ttf);
      /* mem4=*/ aget_int32_be(ttf);
      if (format==0x00020000) {
	 gc=aget_uint16_be(ttf);
	 indexes=calloc(65536, sizeof(uint16_t));
	 /* the index table is backwards from the way I want to use it */
	 gcbig=0;
	 for (i=0; i<gc; ++i) {
	    indexes[val=aget_uint16_be(ttf)]=i;
	    if (val >= 258)
	       ++gcbig;
	 }

	 /* if we are only loading bitmaps, we can get holes in our data */
	 for (i=0; i<258; ++i)
	    if (indexes[i] != 0 || i==0)
	       if (indexes[i]<info->glyph_cnt
		   && info->chars[indexes[i]] != NULL)
		  info->chars[indexes[i]]->name=fastrdup(ttfstandardnames[i]);	/* Too many fonts have badly named glyphs to deduce encoding from name */
	 gcbig += 258;
	 for (i=258; i<gcbig; ++i) {
	    char *nm;

	    len=agetc(ttf);
	    if (len<0)	/* Don't crash on EOF */
	       break;
	    nm=malloc(len+1);
	    for (j=0; j<len; ++j)
	       nm[j]=agetc(ttf);
	    nm[j]='\0';
	    if (indexes[i]<info->glyph_cnt
		&& info->chars[indexes[i]] != NULL)
	       info->chars[indexes[i]]->name=nm;	/* Too many fonts have badly named glyphs to deduce encoding from name */
	 }
	 free(indexes);
	 anynames=true;
      }
   }

   if (info->fd != NULL && info->fd->chars != NULL) {
      EncMap *map=NULL;
      struct pschars *chars=info->fd->chars;

      if (info->map==NULL)
	 info->map=map =
	    EncMapNew(65536, 65536, FindOrMakeEncoding("UnicodeBmp"));
      /* In type42 fonts the names are stored in a postscript /CharStrings dictionary */
      for (i=0; i<chars->next; ++i) {
	 int gid=(intptr_t) (chars->values[i]);

	 if (gid >= 0 && gid<info->glyph_cnt && chars->keys[i] != NULL) {
	    free(info->chars[gid]->name);
	    info->chars[gid]->name=chars->keys[i];
	    info->chars[gid]->unicodeenc =
	       UniFromName(chars->keys[i], info->uni_interp, info->map->enc);
	    if (map != NULL && info->chars[gid]->unicodeenc != -1
		&& info->chars[gid]->unicodeenc<map->enccount)
	       map->map[info->chars[gid]->unicodeenc]=gid;
	    chars->keys[i]=NULL;
	    chars->values[i]=NULL;
	 } else
	    chars->values[i]=NULL;
      }
   }

   for (i=0; i<info->glyph_cnt; ++i)
      if (info->chars[i] != NULL) {
	 /* info->chars[i] can be null in some TTC files */
	 if (i != 0 && info->chars[i]->name != NULL &&
	     strcmp(info->chars[i]->name, ".notdef")==0) {
	    /* for some reason MS puts out fonts where several characters */
	    /* are called .notdef (and only one is a real notdef). So if we */
	    /* find a glyph other than 0 called ".notdef" then pretend it had */
	    /* no name */
	    if (!notdefwarned) {
	       notdefwarned=true;
	       ErrorMsg(2,"Glyph %d is called \".notdef\", a singularly inept choice of name (only glyph 0\n may be called .notdef)\nFontAnvil will rename it.\n",
			i);
	    }
	    free(info->chars[i]->name);
	    info->chars[i]->name=NULL;
	    /* I used to check for glyphs with bad names (ie. names indicative of */
	    /*  another unicode code point than the one applied to the glyph) but */
	    /*  this proves too early for that check, as we don't have the altunis */
	    /*  figured out yet. So I've moved that into its own routine later */
	 }
	 /* And some volt files actually assign nul strings to the name */
	 if ((info->chars[i]->name != NULL && *info->chars[i]->name != '\0'))
	    continue;
	 free(info->chars[i]->name);	/* If it's a null string get rid of it */
	 if (i==0)
	    name=".notdef";
	 else if (info->chars[i]->unicodeenc==-1) {
	    /* Do this later */ ;
	    name=NULL;
	 } else {
	    name =
	       StdGlyphName(buffer, info->chars[i]->unicodeenc,
			    info->uni_interp, NULL);
	    if (anynames) {
	       for (j=0; j<info->glyph_cnt; ++j) {
		  if (info->chars[j] != NULL && j != i
		      && info->chars[j]->name != NULL) {
		     if (strcmp(info->chars[j]->name, name)==0) {
			name=NULL;
			break;
		     }
		  }
	       }
	    }
	 }
	 info->chars[i]->name=fastrdup(name);
      }

   /* If we have a GSUB table we can give some unencoded glyphs names */
   /*  for example if we have a vrt2 substitution of A to <unencoded> */
   /*  we could name the unencoded "A.vrt2" (though in this case we might */
   /*  try A.vert instead */ /* Werner suggested this */
   /* We could try this from morx too, except that apple features don't */
   /*  use meaningful ids. That is A.15,3 isn't very readable */
   for (i=info->glyph_cnt-1; i >= 0; --i)
      if (info->chars[i] != NULL && info->chars[i]->name==NULL)
	 break;
   if (i >= 0 && info->vs_start != 0)
      ApplyVariationSequenceSubtable(ttf, info->vs_start, info,
				     git_findnames);
   if (i >= 0 && info->gsub_start != 0)
      GuessNamesFromGSUB(ttf, info);
   if (i >= 0 && info->math_start != 0)
      GuessNamesFromMATH(ttf, info);

   for (i=0; i<info->glyph_cnt; ++i) {
      /* info->chars[i] can be null in some TTC files */
      if (info->chars[i]==NULL)
	 continue;
      if (info->chars[i]->name != NULL)
	 continue;
      if (info->ordering != NULL)
	 sprintf(buffer, "%.20s-%d", info->ordering, i);
      else if (info->map != NULL && info->map->backmap[i] != -1)
	 sprintf(buffer, "nounicode.%d.%d.%x", info->platform, info->specific,
		 (int) info->map->backmap[i]);
      else
	 sprintf(buffer, "glyph%d", i);
      info->chars[i]->name=fastrdup(buffer);
   }
}

static void readttfgasp(AFILE *ttf,struct ttfinfo *info) {
   int i, cnt;

   if (info->gasp_start==0)
      return;

   afseek(ttf, info->gasp_start, SEEK_SET);
   info->gasp_version=aget_uint16_be(ttf);
   if (info->gasp_version != 0 && info->gasp_version != 1)
      return;			/* We only support 'gasp' versions 0&1 (no other versions currently) */
   info->gasp_cnt=cnt=aget_uint16_be(ttf);
   if (cnt==0)
      return;
   info->gasp=malloc(cnt * sizeof(struct gasp));
   for (i=0; i<cnt; ++i) {
      info->gasp[i].ppem=aget_uint16_be(ttf);
      info->gasp[i].flags=aget_uint16_be(ttf);
   }
}

static void UnfigureControls(Spline *spline,BasePoint *pos) {
   pos->x=rint((spline->splines[0].c+2*spline->splines[0].d)/2);
   pos->y=rint((spline->splines[1].c+2*spline->splines[1].d)/2);
}

int ttfFindPointInSC(SplineChar * sc, int layer, int pnum, BasePoint * pos,
		     RefChar * bound) {
   SplineSet *ss;
   SplinePoint *sp;
   int last=0, ret;
   RefChar *refs;

   for (ss=sc->layers[layer].splines; ss != NULL; ss=ss->next) {
      for (sp=ss->first;;) {
	 if (sp->ttfindex==pnum) {
	    *pos=sp->me;
	    return (-1);
	 } else if (sp->nextcpindex==pnum) {
	    if (sp->next != NULL && sp->next->order2)
	       *pos=sp->nextcp;
	    else {
	       /* fix this up to be 2 degree bezier control point */
	       UnfigureControls(sp->next, pos);
	    }
	    return (-1);
	 }
	 if (!sp->nonextcp && last <= sp->nextcpindex)
	    last=sp->nextcpindex+1;
	 else if (sp->ttfindex != 0xffff)
	    last=sp->ttfindex+1;
	 if (sp->next==NULL)
	    break;
	 sp=sp->next->to;
	 if (sp==ss->first)
	    break;
      }
   }
   for (refs=sc->layers[layer].refs; refs != NULL; refs=refs->next) {
      if (refs==bound) {
	 ErrorMsg(2,"Invalid point match. Point would be after this reference.\n");
	 return (0x800000);
      }
      ret=ttfFindPointInSC(refs->sc, ly_fore, pnum-last, pos, NULL);
      if (ret==-1) {
	 BasePoint p;

	 p.x =
	    refs->transform[0] * pos->x+refs->transform[2] * pos->y +
	    refs->transform[4];
	 p.y =
	    refs->transform[1] * pos->x+refs->transform[3] * pos->y +
	    refs->transform[5];
	 *pos=p;
	 return (-1);
      }
      last += ret;
      if (last>pnum) {
	 ErrorMsg(2,"Point match failure last=%d, pnum=%d\n", last, pnum);
	 return (0x800000);
      }
   }
   return (last);		/* Count of number of points in the character */
}

static void ttfPointMatch(SplineChar *sc,RefChar *rf) {
   BasePoint sofar, inref;

   if (ttfFindPointInSC(sc, ly_fore, rf->match_pt_base, &sofar, rf) != -1 ||
       ttfFindPointInSC(rf->sc, ly_fore, rf->match_pt_ref, &inref,
			NULL) != -1) {
      ErrorMsg(2,"Could not match points in composite glyph (%d to %d) when adding %s to %s\n",
	       rf->match_pt_base, rf->match_pt_ref, rf->sc->name, sc->name);
      return;
   }
   rf->transform[4]=sofar.x-inref.x;
   rf->transform[5]=sofar.y-inref.y;
}

int ttfFixupRef(SplineChar ** chars, int i) {
   RefChar *ref, *prev, *next;

   if (chars[i]==NULL)	/* Can happen in ttc files */
      return (false);
   if (chars[i]->ticked)
      return (false);
   chars[i]->ticked=true;
   prev=NULL;
   for (ref=chars[i]->layers[ly_fore].refs; ref != NULL; ref=next) {
      if (ref->sc != NULL)
	 break;			/* Already done */
      next=ref->next;
      if (!ttfFixupRef(chars, ref->orig_pos)) {
	 if (prev==NULL)
	    chars[i]->layers[ly_fore].refs=next;
	 else
	    prev->next=next;
	 chunkfree(ref, sizeof(RefChar));
      } else {
	 ref->sc=chars[ref->orig_pos];
	 ref->adobe_enc=getAdobeEnc(ref->sc->name);
	 if (ref->point_match)
	    ttfPointMatch(chars[i], ref);
	 SCReinstantiateRefChar(chars[i], ref, ly_fore);
	 SCMakeDependent(chars[i], ref->sc);
	 prev=ref;
      }
   }
   chars[i]->ticked=false;
   return (true);
}

static void ttfFixupReferences(struct ttfinfo *info) {
   int i;

   for (i=0; i<info->glyph_cnt; ++i)
      if (info->chars[i] != NULL)
	 info->chars[i]->ticked=false;
   for (i=0; i<info->glyph_cnt; ++i) {
      ttfFixupRef(info->chars, i);
   }
}

static void TtfCopyTableBlindly(struct ttfinfo *info,AFILE *ttf,
				uint32_t start, uint32_t len, uint32_t tag) {
   struct ttf_table *tab;

   if (start==0 || len==0)
      return;
   if (len>0x1000000) {
      ErrorMsg(2,"Unlikely length for table, so I'm ignoring it. %u\n", len);
      return;
   }

   tab=chunkalloc(sizeof(struct ttf_table));
   tab->tag=tag;
   tab->len=len;
   tab->data=malloc(len);
   afseek(ttf, start, SEEK_SET);
   afread(tab->data, 1, len, ttf);
   tab->next=info->tabs;
   info->tabs=tab;
}

static int LookupListHasFeature(OTLookup *otl,uint32_t tag) {
   FeatureScriptLangList *feat;

   while (otl != NULL) {
      for (feat=otl->features; feat != NULL; feat=feat->next)
	 if (feat->featuretag==tag)
	    return (true);
      otl=otl->next;
   }
   return (false);
}

static int readttf(AFILE *ttf,struct ttfinfo *info,char *filename) {
   int i;

   if (!readttfheader(ttf, info, filename, &info->chosenname)) {
      return (0);
   }
   /* TrueType doesn't need this but opentype dictionaries do */
   readttfpreglyph(ttf, info);

   /* If font only contains bitmaps, then only read bitmaps */
   if ((info->glyphlocations_start==0 || info->glyph_length==0) &&
       info->cff_start==0 && info->typ1_start==0 &&
       info->bitmapdata_start != 0 && info->bitmaploc_start != 0)
      info->onlystrikes=true;

   if (!info->onlystrikes &&
       info->glyphlocations_start != 0 && info->glyph_start != 0 &&
       info->cff_start != 0) {
      info->cff_start=0;
   }

   if (info->onlystrikes) {
      info->chars=calloc(info->glyph_cnt+1, sizeof(SplineChar *));
      info->to_order2=new_fonts_are_order2;
   } else if (info->glyphlocations_start != 0 && info->glyph_start != 0) {
      info->to_order2=(!loaded_fonts_same_as_new ||
			 (loaded_fonts_same_as_new && new_fonts_are_order2));
      /* If it's an apple mm font, then we don't want to change the order */
      /*  This messes up the point count */
      if (info->gvar_start != 0 && info->fvar_start != 0)
	 info->to_order2=true;
      readttfglyphs(ttf, info);
   } else if (info->cff_start != 0) {
      info->to_order2=(loaded_fonts_same_as_new && new_fonts_are_order2);
      if (!readcffglyphs(ttf, info)) {
	 return (0);
      }
   } else if (info->typ1_start != 0) {
      if (!readtyp1glyphs(ttf, info)) {
	 return (0);
      }
   } else {
      return (0);
   }
   if (info->bitmapdata_start != 0 && info->bitmaploc_start != 0)
      TTFLoadBitmaps(ttf, info, info->onlyonestrike);
   else if (info->onlystrikes)
      ErrorMsg(2,"No (useable) bitmap strikes in this TTF font: %s\n",
               filename==NULL?"<unknown>":filename);
   if (info->onlystrikes && info->bitmaps==NULL) {
      free(info->chars);
      return (0);
   }
   if (info->hmetrics_start != 0)
      readttfwidths(ttf, info);
   else if (info->bitmapdata_start != 0 && info->bitmaploc_start != 0)
      dummywidthsfromstrike(ttf, info);
   if (info->vmetrics_start != 0 && info->vhea_start != 0)
      readttfvwidths(ttf, info);
   /* 'cmap' is not meaningful for cid keyed fonts, and not supplied for */
   /*  type42 fonts */
   /* Oops. It is meaningful for cid fonts. It just seemed redundant to me */
   /*  but that was my ignorance. Adobe complains that FF doesn't read it */
   /* (We've already (probably) set the unicodeencs of the glyphs according */
   /*  to the cidmap files, but we can override that here. Mmm. what about a */
   /*  glyph in cidmap but not in cmap???? */
   if (/*info->cidregistry==NULL && */ info->encoding_start != 0)
      readttfencodings(ttf, info, git_normal);
   if (info->os2_start != 0)
      readttfos2metrics(ttf, info);
   readttfpostnames(ttf, info);	/* If no postscript table we'll guess at names */
   if (info->gdef_start != 0)	/* ligature caret positioning info */
      readttfgdef(ttf, info);
   else {
      if (info->prop_start != 0)
	 readttfprop(ttf, info);
      if (info->lcar_start != 0)
	 readttflcar(ttf, info);
   }
   if (info->base_start != 0)
      readttfbase(ttf, info);
   else if (info->bsln_start != 0)
      readttfbsln(ttf, info);
   if (info->gasp_start != 0)
      readttfgasp(ttf, info);
   /* read the cvt table before reading variation data */
   if (info->to_order2) {
      /* Yes, even though we've looked at maxp already, let's make a blind */
      /*  copy too for those fields we can't compute on our own */
      /* Like size of twilight zone, etc. */
      TtfCopyTableBlindly(info, ttf, info->maxp_start, info->maxp_len,
			  CHR('m', 'a', 'x', 'p'));
      TtfCopyTableBlindly(info, ttf, info->cvt_start, info->cvt_len,
			  CHR('c', 'v', 't', ' '));
      TtfCopyTableBlindly(info, ttf, info->fpgm_start, info->fpgm_len,
			  CHR('f', 'p', 'g', 'm'));
      TtfCopyTableBlindly(info, ttf, info->prep_start, info->prep_len,
			  CHR('p', 'r', 'e', 'p'));
   }
   for (i=0; i<info->savecnt; ++i)
      if (info->savetab[i].offset != 0)
	 TtfCopyTableBlindly(info, ttf, info->savetab[i].offset,
			     info->savetab[i].len, info->savetab[i].tag);
   /* Do this before reading kerning info */
   if (info->to_order2 && info->gvar_start != 0 && info->fvar_start != 0)
      readttfvariations(info, ttf);
   if (info->gpos_start != 0)	/* kerning info may live in the gpos table too */
      readttfgpossub(ttf, info, true);
   /* Load the 'kern' table if the GPOS table either didn't exist or didn't */
   /*  contain any kerning info */
   if (info->kern_start != 0
       && !LookupListHasFeature(info->gsplookups[1], CHR('k', 'e', 'r', 'n')))
      readttfkerns(ttf, info);
   if (info->opbd_start != 0
       && !LookupListHasFeature(info->gsplookups[1], CHR('l', 'f', 'b', 'd')))
      readttfopbd(ttf, info);
   if (info->gsub_start != 0)
      readttfgpossub(ttf, info, false);
   if (info->morx_start != 0 || info->mort_start != 0)
      readttfmort(ttf, info);
   if (info->jstf_start != 0)
      readttfjstf(ttf, info);

   if (info->pfed_start != 0)
      pfed_read(ttf, info);
   if (info->tex_start != 0)
      tex_read(ttf, info);
   if (info->math_start != 0)
      otf_read_math(ttf, info);
   if (!info->onlystrikes && info->glyphlocations_start != 0
       && info->glyph_start != 0)
      ttfFixupReferences(info);
   /* Can't fix up any postscript references until we create a SplineFont */
   /*  so the check for cff is delayed. Generally there aren't any cff refs */
   /*  anyway */
   return (true);
}

static void SymbolFixup(struct ttfinfo *info) {
   /* convert a two-byte symbol encoding (one using PUA) into expected */
   /*  one-byte encoding. */
   int i, max;
   EncMap *map=info->map;

   max=-1;
   for (i=map->enccount-1; i >= 0; --i) {
      if (map->map[i]==-1)
	 continue;
      if (i >= 0xf000 && i <= 0xf0ff) {
	 map->map[i-0xf000]=map->map[i];
	 map->map[i]=-1;
	 continue;
      }
      if (i>max)
	 max=i;
   }
   map->enccount=max;
}

void AltUniFigure(SplineFont *sf, EncMap * map, int check_dups) {
   int i, gid;

   if (map->enc != &custom) {
      for (i=0; i<map->enccount; ++i)
	 if ((gid=map->map[i]) != -1) {
	    int uni=UniFromEnc(i, map->enc);

	    if (check_dups)
	       AltUniAdd(sf->glyphs[gid], uni);
	    else
	       AltUniAdd_DontCheckDups(sf->glyphs[gid], uni);
	 }
   }
}

static void NameConsistancyCheck(SplineFont *sf,EncMap *map) {
   /* Many fonts seem to have glyph names which mean something other than */
   /*  what the encoding says of the glyph */
   /* I used to ask about fixing the names up, but people didn't like that */
   /*  so now I just produce warnings */
   int gid, uni;
   SplineChar *sc;

   for (gid=0; gid<sf->glyphcnt; ++gid)
      if ((sc=sf->glyphs[gid]) != NULL) {
	 if (sc->name != NULL &&
	     strcmp(sc->name, ".null") != 0 &&
	     strcmp(sc->name, "nonmarkingreturn") != 0 &&
	     (uni =
	      UniFromName(sc->name, sf->uni_interp,
			  map==NULL?&custom:map->enc)) != -1
	     && sc->unicodeenc != uni) {
	    if (uni >= 0xe000 && uni <= 0xf8ff)
	       /* Don't complain about adobe's old PUA assignments for things like "eight.oldstyle" */
		  ;
	    else if (uni<0x20)
	       /* Nor about control characters */ ;
	    else if (sc->unicodeenc==-1) {
	    } else {
	       /* Ah, but suppose there's an altuni? */
	       struct altuni *alt;

	       for (alt=sc->altuni; alt != NULL && alt->unienc != uni;
		    alt=alt->next);
	       if (alt==NULL) {
		  if (strcmp(sc->name, "alefmaksurainitialarabic")==0 ||
		      strcmp(sc->name, "alefmaksuramedialarabic")==0) {
		     ErrorMsg(2,"The names 'alefmaksurainitialarabic' and 'alefmaksuramedialarabic' in the Adobe Glyph List disagree with Unicode.  The use of these glyph names is therefore discouraged.\n");
		  } else {
		     ErrorMsg(2,"The glyph named %.30s is mapped to U+%04X.\nBut its name indicates it should be mapped to U+%04X.\n",
			      sc->name, sc->unicodeenc, uni);
		  }
	       } else if (alt->vs==0) {
		  alt->unienc=sc->unicodeenc;
		  sc->unicodeenc=uni;
	       }
	    }
	 }
      }
}

static void UseGivenEncoding(SplineFont *sf,struct ttfinfo *info) {
   int i;
   RefChar *rf, *prev, *next;
   SplineChar *sc;

   sf->glyphs=info->chars;
   sf->glyphcnt=sf->glyphmax=info->glyph_cnt;
   for (i=0; i<sf->glyphcnt; ++i)
      if ((sc=sf->glyphs[i]) != NULL) {
	 sc->layers[ly_fore].order2=sc->layers[ly_back].order2 =
	    info->to_order2;
	 sc->parent=sf;
      }

   /* A CFF font could contain type1 charstrings, or a type2 font could use */
   /*  the depreciated convention that endchar =~ seac */
   if (info->cff_length != 0)
      SFInstantiateRefs(sf);

   for (i=0; i<sf->glyphcnt; ++i)
      if (sf->glyphs[i] != NULL) {
	 for (rf=sf->glyphs[i]->layers[ly_fore].refs, prev=NULL;
	      rf != NULL; rf=next) {
	    next=rf->next;
	    if (rf->sc==NULL) {
	       if (prev==NULL)
		  sf->glyphs[i]->layers[ly_fore].refs=next;
	       else
		  prev->next=next;
	       RefCharFree(rf);
	    } else {
	       rf->orig_pos=rf->sc->orig_pos;
	       rf->unicode_enc=rf->sc->unicodeenc;
	       prev=rf;
	    }
	 }
      }
   sf->map=info->map;
   sf->uni_interp=info->uni_interp;
   AltUniFigure(sf, sf->map, false);
   NameConsistancyCheck(sf, sf->map);
}

static char *AxisNameConvert(uint32_t tag) {
   char buffer[8];

   if (tag==CHR('w', 'g', 'h', 't'))
      return (fastrdup("Weight"));
   if (tag==CHR('w', 'd', 't', 'h'))
      return (fastrdup("Width"));
   if (tag==CHR('o', 'p', 's', 'z'))
      return (fastrdup("OpticalSize"));
   if (tag==CHR('s', 'l', 'n', 't'))
      return (fastrdup("Slant"));

   buffer[0]=tag >> 24;
   buffer[1]=tag >> 16;
   buffer[2]=tag >> 8;
   buffer[3]=tag&0xff;
   buffer[4]=0;
   return (fastrdup(buffer));
}

static struct macname *FindMacName(struct ttfinfo *info,int strid) {
   struct macidname *sid;

   for (sid=info->macstrids; sid != NULL; sid=sid->next) {
      if (sid->id==strid)
	 return (sid->head);
   }
   return (NULL);
}

static SplineFont *SFFromTuple(SplineFont *basesf,struct variations *v,
			       int tuple, MMSet * mm, struct ttfinfo *info) {
   SplineFont *sf;
   int i;
   RefChar *r;

   sf=SplineFontEmpty();
   sf->display_size=basesf->display_size;
   sf->display_antialias=basesf->display_antialias;

   sf->fontname=MMMakeMasterFontname(mm, tuple, &sf->fullname);
   sf->familyname=fastrdup(basesf->familyname);
   sf->weight=fastrdup("All");
   sf->italicangle=basesf->italicangle;
   sf->strokewidth=basesf->strokewidth;
   sf->strokedfont=basesf->strokedfont;
   sf->upos=basesf->upos;
   sf->uwidth=basesf->uwidth;
   sf->ascent=basesf->ascent;
   sf->hasvmetrics=basesf->hasvmetrics;
   sf->descent=basesf->descent;
   sf->kerns=v->tuples[tuple].khead;
   sf->vkerns=v->tuples[tuple].vkhead;
   sf->map=basesf->map;
   sf->mm=mm;
   sf->glyphmax=sf->glyphcnt=basesf->glyphcnt;
   sf->glyphs=v->tuples[tuple].chars;
   sf->layers[ly_fore].order2=sf->layers[ly_back].order2=true;
   for (i=0; i<sf->glyphcnt; ++i)
      if (basesf->glyphs[i] != NULL) {
	 SplineChar *sc=sf->glyphs[i];

	 sc->orig_pos=i;
	 sc->parent=sf;
	 sc->layers[ly_fore].order2=sc->layers[ly_back].order2=true;
      }
   sf->grid.order2=true;
   for (i=0; i<sf->glyphcnt; ++i)
      if (sf->glyphs[i] != NULL) {
	 for (r=sf->glyphs[i]->layers[ly_fore].refs; r != NULL; r=r->next)
	    SCReinstantiateRefChar(sf->glyphs[i], r, ly_fore);
      }

   sf->ttf_tables=v->tuples[tuple].cvt;

   v->tuples[tuple].chars=NULL;
   v->tuples[tuple].khead=NULL;
   v->tuples[tuple].vkhead=NULL;
   v->tuples[tuple].cvt=NULL;
   return (sf);
}

static void MMFillFromVAR(SplineFont *sf,struct ttfinfo *info) {
   MMSet *mm=chunkalloc(sizeof(MMSet));
   struct variations *v=info->variations;
   int i, j;

   sf->mm=mm;
   mm->normal=sf;
   mm->apple=true;
   mm->axis_count=v->axis_count;
   mm->instance_count=v->tuple_count;
   mm->instances=malloc(v->tuple_count * sizeof(SplineFont *));
   mm->positions=malloc(v->tuple_count * v->axis_count * sizeof(double));
   for (i=0; i<v->tuple_count; ++i)
      for (j=0; j<v->axis_count; ++j)
	 mm->positions[i * v->axis_count+j]=v->tuples[i].coords[j];
   mm->defweights=calloc(v->tuple_count, sizeof(double));	/* Doesn't apply */
   mm->axismaps=calloc(v->axis_count, sizeof(struct axismap));
   for (i=0; i<v->axis_count; ++i) {
      mm->axes[i]=AxisNameConvert(v->axes[i].tag);
      mm->axismaps[i].min=v->axes[i].min;
      mm->axismaps[i].def=v->axes[i].def;
      mm->axismaps[i].max=v->axes[i].max;
      if (v->axes[i].paircount==0) {
	 mm->axismaps[i].points=3;
	 mm->axismaps[i].blends=malloc(3*sizeof(double));
	 mm->axismaps[i].designs=malloc(3*sizeof(double));
	 mm->axismaps[i].blends[0]=-1;
	 mm->axismaps[i].designs[0]=mm->axismaps[i].min;
	 mm->axismaps[i].blends[1]=0;
	 mm->axismaps[i].designs[1]=mm->axismaps[i].def;
	 mm->axismaps[i].blends[2]=1;
	 mm->axismaps[i].designs[2]=mm->axismaps[i].max;
      } else {
	 mm->axismaps[i].points=v->axes[i].paircount;
	 mm->axismaps[i].blends=malloc(v->axes[i].paircount * sizeof(double));
	 mm->axismaps[i].designs =
	    malloc(v->axes[i].paircount * sizeof(double));
	 for (j=0; j<v->axes[i].paircount; ++j) {
	    if (v->axes[i].mapfrom[j] <= 0) {
	       mm->axismaps[i].designs[j]=mm->axismaps[i].def +
		  v->axes[i].mapfrom[j] * (mm->axismaps[i].def -
					   mm->axismaps[i].min);
	    } else {
	       mm->axismaps[i].designs[j]=mm->axismaps[i].def +
		  v->axes[i].mapfrom[j] * (mm->axismaps[i].max -
					   mm->axismaps[i].def);
	    }
	    mm->axismaps[i].blends[j]=v->axes[i].mapto[j];
	 }
      }
      mm->axismaps[i].axisnames =
	 MacNameCopy(FindMacName(info, v->axes[i].nameid));
   }
   mm->named_instance_count=v->instance_count;
   mm->named_instances =
      malloc(v->instance_count * sizeof(struct named_instance));
   for (i=0; i<v->instance_count; ++i) {
      mm->named_instances[i].coords=v->instances[i].coords;
      v->instances[i].coords=NULL;
      mm->named_instances[i].names =
	 MacNameCopy(FindMacName(info, v->instances[i].nameid));
   }
   for (i=0; i<mm->instance_count; ++i)
      mm->instances[i]=SFFromTuple(sf, v, i, mm, info);
   VariationFree(info);
}

static void PsuedoEncodeUnencoded(EncMap *map,struct ttfinfo *info) {
   int extras, base;
   int i;

   for (i=0; i<info->glyph_cnt; ++i)
      if (info->chars[i] != NULL)
	 info->chars[i]->ticked=false;
   for (i=0; i<map->enccount; ++i)
      if (map->map[i] != -1)
	 info->chars[map->map[i]]->ticked=true;
   extras=0;
   for (i=0; i<info->glyph_cnt; ++i)
      if (info->chars[i] != NULL && !info->chars[i]->ticked)
	 ++extras;
   if (extras != 0) {
      if (map->enccount <= 256)
	 base=256;
      else if (map->enccount <= 65536)
	 base=65536;
      else if (map->enccount <= 17*65536)
	 base=17*65536;
      else
	 base=map->enccount;
      if (base+extras>map->encmax) {
	 map->map=realloc(map->map, (base+extras)*sizeof(int));
	 memset(map->map+map->enccount, -1,
		(base+extras-map->enccount)*sizeof(int));
	 map->encmax=base+extras;
      }
      map->enccount=base+extras;
      extras=0;
      for (i=0; i<info->glyph_cnt; ++i)
	 if (info->chars[i] != NULL && !info->chars[i]->ticked)
	    map->map[base+extras++]=i;
   }
}

static void MapDoBack(EncMap *map,struct ttfinfo *info) {
   int i;

   if (map==NULL)		/* CID fonts */
      return;
   free(map->backmap);		/* CFF files have this */
   map->backmax=info->glyph_cnt;
   map->backmap=malloc(info->glyph_cnt * sizeof(int));
   memset(map->backmap, -1, info->glyph_cnt * sizeof(int));
   for (i=map->enccount-1; i >= 0; --i)
      if (map->map[i] >= 0 && map->map[i]<info->glyph_cnt)
	 if (map->backmap[map->map[i]]==-1)
	    map->backmap[map->map[i]]=i;
}

void TTF_PSDupsDefault(SplineFont *sf) {
   struct ttflangname *english;
   char versionbuf[40];

   /* Ok, if we've just loaded a ttf file then we've got a bunch of langnames */
   /*  we copied some of them (copyright, family, fullname, etc) into equiv */
   /*  postscript entries in the sf. If we then use FontInfo and change the */
   /*  obvious postscript entries we are left with the old ttf entries. If */
   /*  we generate a ttf file and then load it the old values pop up. */
   /* Solution: Anything we can generate by default should be set to NULL */
   for (english=sf->names; english != NULL && english->lang != 0x409;
	english=english->next);
   if (english==NULL)
      return;
   if (english->names[ttf_family] != NULL &&
       strcmp(english->names[ttf_family], sf->familyname)==0) {
      free(english->names[ttf_family]);
      english->names[ttf_family]=NULL;
   }
   if (english->names[ttf_copyright] != NULL &&
       strcmp(english->names[ttf_copyright], sf->copyright)==0) {
      free(english->names[ttf_copyright]);
      english->names[ttf_copyright]=NULL;
   }
   if (english->names[ttf_fullname] != NULL &&
       strcmp(english->names[ttf_fullname], sf->fullname)==0) {
      free(english->names[ttf_fullname]);
      english->names[ttf_fullname]=NULL;
   }
   if (sf->subfontcnt != 0 || sf->version != NULL) {
      if (sf->subfontcnt != 0)
	 sprintf(versionbuf, "Version %f", sf->cidversion);
      else
	 sprintf(versionbuf, "Version %.20s ", sf->version);
      if (english->names[ttf_version] != NULL &&
	  strcmp(english->names[ttf_version], versionbuf)==0) {
	 free(english->names[ttf_version]);
	 english->names[ttf_version]=NULL;
      }
   }
   if (english->names[ttf_subfamily] != NULL &&
       strcmp(english->names[ttf_subfamily], SFGetModifiers(sf))==0) {
      free(english->names[ttf_subfamily]);
      english->names[ttf_subfamily]=NULL;
   }

   /* User should not be allowed any access to this one, not ever */
   free(english->names[ttf_postscriptname]);
   english->names[ttf_postscriptname]=NULL;
}

static void ASCIIcheck(char **str) {

   if (*str != NULL && !AllAscii(*str)) {
      char *temp=StripToASCII(*str);

      free(*str);
      *str=temp;
   }
}

static SplineFont *SFFillFromTTF(struct ttfinfo *info) {
   SplineFont *sf, *_sf;
   int i, k;
   BDFFont *bdf;
   SplineChar *sc;
   struct ttf_table *last[2], *tab, *next;

   sf=SplineFontEmpty();
   sf->display_size=-default_fv_font_size;
   sf->display_antialias=default_fv_antialias;
   sf->fontname=info->fontname;
   sf->fullname=info->fullname;
   sf->familyname=info->familyname;
   sf->chosenname=info->chosenname;
   sf->onlybitmaps=info->onlystrikes;
   sf->layers[ly_fore].order2=info->to_order2;
   sf->layers[ly_back].order2=info->to_order2;
   sf->grid.order2=info->to_order2;
   sf->comments=info->fontcomments;
   sf->fontlog=info->fontlog;
   sf->cvt_names=info->cvt_names;

   sf->creationtime=info->creationtime;
   sf->modificationtime=info->modificationtime;

   sf->design_size=info->design_size;
   sf->design_range_bottom=info->design_range_bottom;
   sf->design_range_top=info->design_range_top;
   sf->fontstyle_id=info->fontstyle_id;
   sf->fontstyle_name=info->fontstyle_name;
   sf->feat_names=info->feat_names;

   sf->gasp_cnt=info->gasp_cnt;
   sf->gasp=info->gasp;
   sf->MATH=info->math;

   sf->texdata=info->texdata;

   sf->mark_class_cnt=info->mark_class_cnt;
   sf->mark_classes=info->mark_classes;
   sf->mark_class_names=info->mark_class_names;

   sf->mark_set_cnt=info->mark_set_cnt;
   sf->mark_sets=info->mark_sets;
   sf->mark_set_names=info->mark_set_names;

   if (info->fd != NULL) {	/* Special hack for type42 fonts */
      sf->fontname=fastrdup(info->fd->fontname);
      sf->uniqueid=info->fd->uniqueid;
      sf->xuid=XUIDFromFD(info->fd->xuid);
      if (info->fd->fontinfo != NULL) {
	 sf->familyname=utf8_verify_copy(info->fd->fontinfo->familyname);
	 sf->fullname=utf8_verify_copy(info->fd->fontinfo->fullname);
	 sf->copyright=utf8_verify_copy(info->fd->fontinfo->notice);
	 sf->weight=utf8_verify_copy(info->fd->fontinfo->weight);
	 sf->version=utf8_verify_copy(info->fd->fontinfo->version);
	 sf->italicangle=info->fd->fontinfo->italicangle;
	 sf->upos =
	    info->fd->fontinfo->underlineposition * (sf->ascent +
						     sf->descent);
	 sf->uwidth =
	    info->fd->fontinfo->underlinethickness * (sf->ascent +
						      sf->descent);
      }
   }

   if (sf->fontname==NULL) {
      sf->fontname=EnforcePostScriptName(sf->fullname);
      if (sf->fontname==NULL)
	 sf->fontname=EnforcePostScriptName(sf->familyname);
      if (sf->fontname==NULL)
	 sf->fontname=EnforcePostScriptName("UntitledTTF");
   }
   if (sf->fullname==NULL)
      sf->fullname=fastrdup(sf->fontname);
   if (sf->familyname==NULL)
      sf->familyname=fastrdup(sf->fontname);
   if (sf->weight==NULL) {
      if (info->weight != NULL)
	 sf->weight=info->weight;
      else if (info->pfminfo.pfmset)
	 sf->weight=fastrdup(info->pfminfo.weight <= 100?"Thin" :
			   info->pfminfo.weight <= 200?"Extra-Light" :
			   info->pfminfo.weight <= 300?"Light" :
			   info->pfminfo.weight <= 400?"Book" :
			   info->pfminfo.weight <= 500?"Medium" :
			   info->pfminfo.weight <= 600?"Demi" :
			   info->pfminfo.weight <= 700?"Bold" :
			   info->pfminfo.weight <= 800?"Heavy":"Black");
      else
	 sf->weight=fastrdup("");
   } else
      free(info->weight);
   if (sf->copyright==NULL)
      sf->copyright=info->copyright;
   else
      free(info->copyright);
   sf->version=info->version;
   sf->italicangle=info->italicAngle;
   sf->strokewidth=info->strokewidth;
   sf->strokedfont=info->strokedfont;
   sf->upos=info->upos;
   sf->uwidth=info->uwidth;
   sf->ascent=info->ascent;
   if (info->vhea_start != 0 && info->vmetrics_start != 0)
      sf->hasvmetrics=true;
   sf->descent=info->descent;
   sf->private=info->private;
   sf->xuid=info->xuid;
   sf->uniqueid=info->uniqueid;
   sf->pfminfo=info->pfminfo;
   sf->os2_version=info->os2_version;
   sf->sfntRevision=info->sfntRevision;
   sf->use_typo_metrics=info->use_typo_metrics;
   sf->weight_width_slope_only=info->weight_width_slope_only;
   sf->head_optimized_for_cleartype=info->optimized_for_cleartype;
   sf->gasp_version=info->gasp_version;
   sf->names=info->names;
   sf->anchor=info->ahead;
   sf->kerns=info->khead;
   sf->vkerns=info->vkhead;
   sf->possub=info->possub;
   sf->sm=info->sm;
   sf->features=info->features;
   sf->gsplookups[0]=info->gsplookups[0];
   sf->gsplookups[1]=info->gsplookups[1];

   last[0]=sf->ttf_tables;
   last[1]=NULL;
   for (tab=info->tabs; tab != NULL; tab=next) {
      next=tab->next;
      if (tab->tag==CHR('f', 'p', 'g', 'm')
	  || tab->tag==CHR('p', 'r', 'e', 'p')
	  || tab->tag==CHR('c', 'v', 't', ' ')
	  || tab->tag==CHR('m', 'a', 'x', 'p')) {
	 if (last[0]==NULL)
	    sf->ttf_tables=tab;
	 else
	    last[0]->next=tab;
	 last[0]=tab;
      } else {
	 if (last[1]==NULL)
	    sf->ttf_tab_saved=tab;
	 else
	    last[1]->next=tab;
	 last[1]=tab;
      }
      tab->next=NULL;
   }

   if (info->twobytesymbol)
      /* rework ms symbol encodings */
      SymbolFixup(info);
   if (info->map==NULL && info->subfonts==NULL)	/* Can happen when reading a ttf from a pdf */
      info->map=EncMapFromEncoding(sf, FindOrMakeEncoding("original"));
   if (info->subfontcnt==0)
      PsuedoEncodeUnencoded(info->map, info);
   MapDoBack(info->map, info);
   sf->map=info->map;
   sf->cidregistry=info->cidregistry;
   sf->ordering=info->ordering;
   sf->supplement=info->supplement;
   sf->cidversion=info->cidfontversion;
   sf->bitmaps=info->bitmaps;
   sf->grid=info->guidelines;
   sf->horiz_base=info->horiz_base;
   sf->vert_base=info->vert_base;
   sf->justify=info->justify;
   for (bdf=info->bitmaps; bdf != NULL; bdf=bdf->next) {
      bdf->sf=sf;
   }
   SFDefaultAscent(sf);
   if (info->layers != NULL) {
      info->layers[ly_fore]=sf->layers[ly_fore];
      sf->layers[ly_fore].name=NULL;
      if (info->layers[ly_back].name==NULL)
	 info->layers[ly_back].name=sf->layers[ly_back].name;
      else
	 free(sf->layers[ly_back].name);
      free(sf->layers);
      sf->layers=info->layers;
      sf->layer_cnt=info->layer_cnt;
   }


   for (i=0; i<info->glyph_cnt; ++i)
      if (info->chars[i] != NULL) {
	 SCOrderAP(info->chars[i]);
      }

   if (info->subfontcnt==0) {
      UseGivenEncoding(sf, info);
   } else {
      sf->subfontcnt=info->subfontcnt;
      sf->subfonts=info->subfonts;
      free(info->chars);	/* This is the GID->char index, don't need it now */
      for (i=0; i<sf->subfontcnt; ++i) {
	 sf->subfonts[i]->cidmaster=sf;
	 sf->subfonts[i]->hasvmetrics=sf->hasvmetrics;
      }
   }
   ASCIIcheck(&sf->copyright);
   ASCIIcheck(&sf->familyname);
   ASCIIcheck(&sf->weight);
   ASCIIcheck(&sf->version);

   TTF_PSDupsDefault(sf);

   /* I thought the languages were supposed to be ordered, but it seems */
   /*  that is not always the case. Order everything, just in case */
   {
      int isgpos;
      OTLookup *otl;

      for (isgpos=0; isgpos<2; ++isgpos)
	 for (otl=sf->gsplookups[isgpos];otl!=NULL;otl=otl->next)
	    otl->features=FLOrder(otl->features);
   }

   if (info->variations != NULL)
      MMFillFromVAR(sf, info);

   if (info->cff_length != 0 && !sf->layers[ly_fore].order2) {
      /* Clean up the hint masks, We create an initial hintmask whether we */
      /*  need it or not */
      k=0;
      do {
	 _sf=k<sf->subfontcnt?sf->subfonts[k]:sf;
	 for (i=0; i<sf->glyphcnt; ++i) {
	    if ((sc=_sf->glyphs[i]) != NULL && !sc->hconflicts
		&& !sc->vconflicts && sc->layers[ly_fore].splines != NULL) {
	       chunkfree(sc->layers[ly_fore].splines->first->hintmask,
			 sizeof(HintMask));
	       sc->layers[ly_fore].splines->first->hintmask=NULL;
	    }
	 }
	 ++k;
      } while (k<sf->subfontcnt);
   }
   /* should not be default as it confuses users */
   /* SFRelativeWinAsDs(sf); */
   free(info->savetab);

   if (info->openflags&of_fontlint) {
      k=0;
      do {
	 _sf=k<sf->subfontcnt?sf->subfonts[k]:sf;
	 for (i=0; i<sf->glyphcnt; ++i) {
	    if ((sc=_sf->glyphs[i]) != NULL) {
	       DBounds b;

	       SplineCharQuickBounds(sc, &b);
	       if (b.minx==0 && b.maxx==0)
		  /* Skip it, no points */ ;
	       else if (b.minx<info->fbb[0] || b.miny<info->fbb[1] ||
			b.maxx>info->fbb[2] || b.maxy>info->fbb[3]) {
		  ErrorMsg(2,"A point in %s is outside the font bounding box data.\n",
			   sc->name);
		  info->bad_cff=true;
	       }
	       if (info->isFixedPitch && i>2
		   && sc->width != info->advanceWidthMax)
		  ErrorMsg(2,"The advance width of %s (%d) does not match the font's advanceWidthMax (%d) and this is a fixed pitch font\n",
			   sc->name, sc->width, info->advanceWidthMax);
	    }
	 }
	 ++k;
      } while (k<sf->subfontcnt);
   }

   sf->loadvalidation_state =
      (info->bad_ps_fontname?lvs_bad_ps_fontname:0) |
      (info->bad_glyph_data?lvs_bad_glyph_table:0) |
      (info->bad_cff?lvs_bad_cff_table:0) |
      (info->bad_metrics?lvs_bad_metrics_table:0) |
      (info->bad_cmap?lvs_bad_cmap_table:0) |
      (info->bad_embedded_bitmap?lvs_bad_bitmaps_table:0) |
      (info->bad_gx?lvs_bad_gx_table:0) |
      (info->bad_ot?lvs_bad_ot_table:0) |
      (info->bad_os2_version?lvs_bad_os2_version:0) |
      (info->bad_sfnt_header?lvs_bad_sfnt_header:0);
   return (sf);
}

SplineFont *_SFReadTTF(AFILE *ttf, int flags, enum openflags openflags,
		       char *filename, struct fontdict * fd) {
   struct ttfinfo info;
   int ret;

   memset(&info, '\0', sizeof(struct ttfinfo));
   info.onlystrikes=(flags&ttf_onlystrikes)?1:0;
   info.onlyonestrike=(flags&ttf_onlyonestrike)?1:0;
   info.use_typo_metrics=true;
   info.openflags=openflags;
   info.fd=fd;
   ret=readttf(ttf, &info, filename);
   if (!ret)
      return (NULL);
   return (SFFillFromTTF(&info));
}

SplineFont *SFReadTTF(char *filename, int flags, enum openflags openflags) {
   AFILE *ttf;
   SplineFont *sf;
   char *temp=filename, *pt, *lparen, *rparen;

   pt=strrchr(filename, '/');
   if (pt==NULL)
      pt=filename;
   if ((lparen=strrchr(pt, '(')) != NULL &&
       (rparen=strrchr(lparen, ')')) != NULL && rparen[1]=='\0') {
      temp=fastrdup(filename);
      pt=temp+(lparen-filename);
      *pt='\0';
   }
   ttf=afopen(temp, "rb");
   if (temp != filename)
      free(temp);
   if (ttf==NULL)
      return (NULL);

   sf=_SFReadTTF(ttf, flags, openflags, filename, NULL);
   afclose(ttf);
   return (sf);
}

SplineFont *_CFFParse(AFILE *temp, int len, char *fontsetname) {
   struct ttfinfo info;

   memset(&info, '\0', sizeof(info));
   info.cff_start=0;
   info.cff_length=len;
   info.barecff=true;
   if (!readcffglyphs(temp, &info))
      return (NULL);
   return (SFFillFromTTF(&info));
}

SplineFont *CFFParse(char *filename) {
   AFILE *cff=afopen(filename, "r");
   SplineFont *sf;
   long len;

   if (cff==NULL)
      return (NULL);
   afseek(cff, 0, SEEK_END);
   len=aftell(cff);
   afseek(cff, 0, SEEK_SET);
   sf=_CFFParse(cff, len, NULL);
   afclose(cff);
   return (sf);
}

char **NamesReadCFF(char *filename) {
   AFILE *cff=afopen(filename, "rb");
   int32_t hdrsize, offsize;
   char **fontnames;

   if (cff==NULL)
      return (NULL);
   if (agetc(cff) != '\1') {	/* Major version */
      ErrorMsg(2,"CFF version mismatch\n");
      afclose(cff);
      return (NULL);
   }
   agetc(cff);			/* Minor version */
   hdrsize=agetc(cff);
   offsize=agetc(cff);
   if (hdrsize != 4)
      afseek(cff, hdrsize, SEEK_SET);
   fontnames=readcfffontnames(cff, NULL, NULL);
   afclose(cff);
   return (fontnames);
}

char **NamesReadTTF(char *filename) {
   AFILE *ttf=afopen(filename, "rb");
   int32_t version, cnt, *offsets;
   int i, j;
   char **ret=NULL;
   char *temp;

   if (ttf==NULL)
      return (NULL);
   version=aget_int32_be(ttf);
   if (version==CHR('t', 't', 'c', 'f')) {
      /* TTCF version=*/ aget_int32_be(ttf);
      cnt=aget_int32_be(ttf);
      offsets=malloc(cnt * sizeof(int32_t));
      for (i=0; i<cnt; ++i)
	 offsets[i]=aget_int32_be(ttf);
      ret=malloc((cnt+1)*sizeof(char *));
      for (i=j=0; i<cnt; ++i) {
	 temp=TTFGetFontName(ttf, offsets[i], 0);
	 if (temp != NULL)
	    ret[j++]=temp;
      }
      ret[j]=NULL;
      free(offsets);
   } else {
      temp=TTFGetFontName(ttf, 0, 0);
      if (temp != NULL) {
	 ret=malloc(2*sizeof(char *));
	 ret[0]=temp;
	 ret[1]=NULL;
      }
   }
   afclose(ttf);
   return (ret);
}
