]> www.fi.muni.cz Git - evince.git/blobdiff - pdf/xpdf/FontFile.cc
Imported Xpdf 2.03 and fixed build.
[evince.git] / pdf / xpdf / FontFile.cc
index 56807a4b9157aee6d7e1f90a08ff51236cf11d6d..0c44422906a767c670d989875312fcc5a504cd0d 100644 (file)
@@ -2,22 +2,25 @@
 //
 // FontFile.cc
 //
-// Copyright 1999-2002 Glyph & Cog, LLC
+// Copyright 1999-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
 #pragma implementation
 #endif
 
-#include <aconf.h>
 #include <locale.h>
 #include <math.h>
 #include <stdlib.h>
 #include <stddef.h>
+#include <stdarg.h>
 #include <string.h>
 #include <ctype.h>
 #include "gmem.h"
+#include "GHash.h"
 #include "Error.h"
 #include "GlobalParams.h"
 #include "CharCodeToUnicode.h"
@@ -31,7 +34,7 @@
 static inline char *nextLine(char *line, char *end) {
   while (line < end && *line != '\n' && *line != '\r')
     ++line;
-  while (line < end && *line == '\n' || *line == '\r')
+  while (line < end && (*line == '\n' || *line == '\r'))
     ++line;
   return line;
 }
@@ -188,31 +191,38 @@ struct Type1CPrivateDict {
 };
 
 Type1CFontFile::Type1CFontFile(char *fileA, int lenA) {
-  Guchar *nameIdxPtr, *idxPtr0, *idxPtr1;
+  int nameIdxPos, namePos, nameLen;
 
-  file = fileA;
+  file = (Guchar *)fileA;
   len = lenA;
   name = NULL;
   encoding = NULL;
+  ok = gFalse;
 
   // some tools embed Type 1C fonts with an extra whitespace char at
   // the beginning
-  if (file[0] != '\x01') {
+  if (len > 0 && file[0] != '\x01') {
     ++file;
+    --len;
   }
 
-  // read header
-  topOffSize = file[3] & 0xff;
+  // make sure the header exists
+  if (len < 4) {
+    return;
+  }
 
   // read name index (first font only)
-  nameIdxPtr = (Guchar *)file + (file[2] & 0xff);
-  idxPtr0 = getIndexValPtr(nameIdxPtr, 0);
-  idxPtr1 = getIndexValPtr(nameIdxPtr, 1);
-  name = new GString((char *)idxPtr0, idxPtr1 - idxPtr0);
-
-  topDictIdxPtr = getIndexEnd(nameIdxPtr);
-  stringIdxPtr = getIndexEnd(topDictIdxPtr);
-  gsubrIdxPtr = getIndexEnd(stringIdxPtr);
+  nameIdxPos = file[2] & 0xff;
+  if ((namePos = getIndexValPos(nameIdxPos, 0, &nameLen)) < 0) {
+    return;
+  }
+  name = new GString((char *)&file[namePos], nameLen);
+
+  topDictIdxPos = getIndexEnd(nameIdxPos);
+  stringIdxPos = getIndexEnd(topDictIdxPos);
+  gsubrIdxPos = getIndexEnd(stringIdxPos);
+
+  ok = gTrue;
 }
 
 Type1CFontFile::~Type1CFontFile() {
@@ -233,14 +243,14 @@ char *Type1CFontFile::getName() {
 
 char **Type1CFontFile::getEncoding() {
   if (!encoding) {
-    readNameAndEncoding();
+    readEncoding();
   }
   return encoding;
 }
 
-void Type1CFontFile::readNameAndEncoding() {
+void Type1CFontFile::readEncoding() {
   char buf[256];
-  Guchar *idxPtr0, *idxPtr1, *ptr;
+  int idxPos, idxLen, pos;
   int nGlyphs;
   int nCodes, nRanges, nLeft, nSups;
   Gushort *glyphNames;
@@ -258,16 +268,20 @@ void Type1CFontFile::readNameAndEncoding() {
   }
 
   // read top dict (first font only)
-  idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
-  idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
+  if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) {
+    return;
+  }
   charset = enc = charstrings = 0;
   i = 0;
-  ptr = idxPtr0;
-  while (ptr < idxPtr1) {
-    if (*ptr <= 27 || *ptr == 31) {
-      key = *ptr++;
+  pos = idxPos;
+  while (pos < idxPos + idxLen) {
+    if (file[pos] <= 27 || file[pos] == 31) {
+      key = file[pos++];
       if (key == 0x0c) {
-       key = (key << 8) | *ptr++;
+       if (pos >= idxPos + idxLen) {
+         return;
+       }
+       key = (key << 8) | file[pos++];
       }
       if (key == 0x0f) { // charset
        charset = (int)op[0];
@@ -278,7 +292,7 @@ void Type1CFontFile::readNameAndEncoding() {
       }
       i = 0;
     } else {
-      x = getNum(&ptr, &isFP);
+      x = getNum(&pos, &isFP);
       if (i < 48) {
        op[i++] = x;
       }
@@ -286,7 +300,7 @@ void Type1CFontFile::readNameAndEncoding() {
   }
 
   // get number of glyphs from charstrings index
-  nGlyphs = getIndexLen((Guchar *)file + charstrings);
+  nGlyphs = getIndexLen(charstrings);
 
   // read charset (GID -> name mapping)
   glyphNames = readCharset(charset, nGlyphs);
@@ -305,178 +319,274 @@ void Type1CFontFile::readNameAndEncoding() {
       }
     }
   } else {
-    ptr = (Guchar *)file + enc;
-    encFormat = *ptr++;
+    pos = enc;
+    if (pos < 0 || pos >= len) {
+      goto err0;
+    }
+    encFormat = file[pos++];
     if ((encFormat & 0x7f) == 0) {
-      nCodes = 1 + *ptr++;
+      if (pos >= len) {
+       goto err0;
+      }
+      nCodes = 1 + file[pos++];
       if (nCodes > nGlyphs) {
        nCodes = nGlyphs;
       }
+      if (pos + nCodes - 1 > len) {
+       goto err0;
+      }
       for (i = 1; i < nCodes; ++i) {
-       c = *ptr++;
+       c = file[pos++];
+       if (encoding[c]) {
+         gfree(encoding[c]);
+       }
        encoding[c] = copyString(getString(glyphNames[i], buf));
       }
     } else if ((encFormat & 0x7f) == 1) {
-      nRanges = *ptr++;
+      if (pos >= len) {
+       goto err0;
+      }
+      nRanges = file[pos++];
+      if (pos + 2 * nRanges > len) {
+       goto err0;
+      }
       nCodes = 1;
       for (i = 0; i < nRanges; ++i) {
-       c = *ptr++;
-       nLeft = *ptr++;
+       c = file[pos++];
+       nLeft = file[pos++];
        for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
-         encoding[c] = copyString(getString(glyphNames[nCodes], buf));
+         if (c < 256) {
+           if (encoding[c]) {
+             gfree(encoding[c]);
+           }
+           encoding[c] = copyString(getString(glyphNames[nCodes], buf));
+         }
          ++nCodes;
          ++c;
        }
       }
     }
     if (encFormat & 0x80) {
-      nSups = *ptr++;
+      if (pos >= len) {
+       goto err0;
+      }
+      nSups = file[pos++];
+      if (pos + nSups * 3 > len) {
+       goto err0;
+      }
       for (i = 0; i < nSups; ++i) {
-       c = *ptr++;
-       sid = getWord(ptr, 2);
-       ptr += 2;
+       c = file[pos++];
+       sid = getWord(pos, 2);
+       pos += 2;
+       if (encoding[c]) {
+         gfree(encoding[c]);
+       }
        encoding[c] = copyString(getString(sid, buf));
       }
     }
   }
 
-  if (charset > 2) {
+ err0:
+  if (charset < 0 || charset > 2) {
     gfree(glyphNames);
   }
 }
 
-void Type1CFontFile::convertToType1(FILE *outA) {
+void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
+                                   void *outputStreamA) {
   Type1CTopDict dict;
   Type1CPrivateDict privateDict;
-  char buf[256], eBuf[256];
-  Guchar *idxPtr0, *idxPtr1, *subrsIdxPtr, *charStringsIdxPtr, *ptr;
+  char buf[512], eBuf[256];
+  int idxPos, idxLen, pos;
   int nGlyphs, nCodes, nRanges, nLeft, nSups;
   Gushort *glyphNames;
-  int encFormat, nSubrs, nCharStrings;
+  int encFormat, nCharStrings;
   int c, sid;
-  int i, j, n;
+  int i, j;
 
-  out = outA;
+  outputFunc = outputFuncA;
+  outputStream = outputStreamA;
 
   // read top dict (first font only)
   readTopDict(&dict);
 
-  // get global subrs
-  //~ ... global subrs are unimplemented
-
   // write header and font dictionary, up to encoding
-  fprintf(out, "%%!FontType1-1.0: %s", name->getCString());
+  (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17);
+  (*outputFunc)(outputStream, name->getCString(), name->getLength());
   if (dict.version != 0) {
-    fprintf(out, "%s", getString(dict.version, buf));
+    getString(dict.version, buf);
+    (*outputFunc)(outputStream, buf, strlen(buf));
   }
-  fprintf(out, "\n");
-  fprintf(out, "11 dict begin\n");
-  fprintf(out, "/FontInfo 10 dict dup begin\n");
+  (*outputFunc)(outputStream, "\n", 1);
+  // the dictionary needs room for 12 entries: the following 9, plus
+  // Private and CharStrings (in the eexec section) and FID (which is
+  // added by definefont)
+  (*outputFunc)(outputStream, "12 dict begin\n", 14);
+  (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28);
   if (dict.version != 0) {
-    fprintf(out, "/version (%s) readonly def\n",
-           getString(dict.version, buf));
+    (*outputFunc)(outputStream, "/version (", 10);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, ") readonly def\n", 15);
   }
   if (dict.notice != 0) {
-    fprintf(out, "/Notice (%s) readonly def\n",
-           getString(dict.notice, buf));
+    getString(dict.notice, buf);
+    (*outputFunc)(outputStream, "/Notice (", 9);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, ") readonly def\n", 15);
   }
   if (dict.copyright != 0) {
-    fprintf(out, "/Copyright (%s) readonly def\n",
-           getString(dict.copyright, buf));
+    getString(dict.copyright, buf);
+    (*outputFunc)(outputStream, "/Copyright (", 12);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, ") readonly def\n", 15);
   }
   if (dict.fullName != 0) {
-    fprintf(out, "/FullName (%s) readonly def\n",
-           getString(dict.fullName, buf));
+    getString(dict.fullName, buf);
+    (*outputFunc)(outputStream, "/FullName (", 11);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, ") readonly def\n", 15);
   }
   if (dict.familyName != 0) {
-    fprintf(out, "/FamilyName (%s) readonly def\n",
-           getString(dict.familyName, buf));
+    getString(dict.familyName, buf);
+    (*outputFunc)(outputStream, "/FamilyName (", 13);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, ") readonly def\n", 15);
   }
   if (dict.weight != 0) {
-    fprintf(out, "/Weight (%s) readonly def\n",
-           getString(dict.weight, buf));
-  }
-  fprintf(out, "/isFixedPitch %s def\n", dict.isFixedPitch ? "true" : "false");
-  fprintf(out, "/ItalicAngle %g def\n", dict.italicAngle);
-  fprintf(out, "/UnderlinePosition %g def\n", dict.underlinePosition);
-  fprintf(out, "/UnderlineThickness %g def\n", dict.underlineThickness);
-  fprintf(out, "end readonly def\n");
-  fprintf(out, "/FontName /%s def\n", name->getCString());
-  fprintf(out, "/PaintType %d def\n", dict.paintType);
-  fprintf(out, "/FontType 1 def\n");
-  fprintf(out, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
+    getString(dict.weight, buf);
+    (*outputFunc)(outputStream, "/Weight (", 9);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, ") readonly def\n", 15);
+  }
+  if (dict.isFixedPitch) {
+    (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23);
+  } else {
+    (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24);
+  }
+  sprintf(buf, "/ItalicAngle %g def\n", dict.italicAngle);
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  sprintf(buf, "/UnderlinePosition %g def\n", dict.underlinePosition);
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  sprintf(buf, "/UnderlineThickness %g def\n", dict.underlineThickness);
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  (*outputFunc)(outputStream, "end readonly def\n", 17);
+  (*outputFunc)(outputStream, "/FontName /", 11);
+  (*outputFunc)(outputStream, name->getCString(), name->getLength());
+  (*outputFunc)(outputStream, " def\n", 5);
+  sprintf(buf, "/PaintType %d def\n", dict.paintType);
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+  sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] readonly def\n",
          dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
          dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
-  fprintf(out, "/FontBBox [%g %g %g %g] readonly def\n",
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  sprintf(buf, "/FontBBox [%g %g %g %g] readonly def\n",
          dict.fontBBox[0], dict.fontBBox[1],
          dict.fontBBox[2], dict.fontBBox[3]);
-  fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth);
+  (*outputFunc)(outputStream, buf, strlen(buf));
   if (dict.uniqueID != 0) {
-    fprintf(out, "/UniqueID %d def\n", dict.uniqueID);
+    sprintf(buf, "/UniqueID %d def\n", dict.uniqueID);
+    (*outputFunc)(outputStream, buf, strlen(buf));
   }
 
   // get number of glyphs from charstrings index
-  nGlyphs = getIndexLen((Guchar *)file + dict.charStrings);
+  nGlyphs = getIndexLen(dict.charStrings);
 
   // read charset
   glyphNames = readCharset(dict.charset, nGlyphs);
 
   // read encoding (glyph -> code mapping), write Type 1 encoding
-  fprintf(out, "/Encoding ");
+  (*outputFunc)(outputStream, "/Encoding ", 10);
   if (dict.encoding == 0) {
-    fprintf(out, "StandardEncoding def\n");
+    (*outputFunc)(outputStream, "StandardEncoding def\n", 21);
   } else {
-    fprintf(out, "256 array\n");
-    fprintf(out, "0 1 255 {1 index exch /.notdef put} for\n");
+    (*outputFunc)(outputStream, "256 array\n", 10);
+    (*outputFunc)(outputStream,
+                 "0 1 255 {1 index exch /.notdef put} for\n", 40);
     if (dict.encoding == 1) {
       for (i = 0; i < 256; ++i) {
        if (expertEncoding[i]) {
-         fprintf(out, "dup %d /%s put\n", i, expertEncoding[i]);
+         sprintf(buf, "dup %d /%s put\n", i, expertEncoding[i]);
+         (*outputFunc)(outputStream, buf, strlen(buf));
        }
       }
     } else {
-      ptr = (Guchar *)file + dict.encoding;
-      encFormat = *ptr++;
+      pos = dict.encoding;
+      if (pos < 0 || pos >= len) {
+       goto err0;
+      }
+      encFormat = file[pos++];
       if ((encFormat & 0x7f) == 0) {
-       nCodes = 1 + *ptr++;
+       if (pos >= len) {
+         goto err0;
+       }
+       nCodes = 1 + file[pos++];
        if (nCodes > nGlyphs) {
          nCodes = nGlyphs;
        }
+       if (pos + nCodes - 1 > len) {
+         goto err0;
+       }
        for (i = 1; i < nCodes; ++i) {
-         c = *ptr++;
-         fprintf(out, "dup %d /%s put\n",
-                 c, getString(glyphNames[i], buf));
+         c = file[pos++];
+         sprintf(buf, "dup %d /", c);
+         (*outputFunc)(outputStream, buf, strlen(buf));
+         getString(glyphNames[i], buf);
+         (*outputFunc)(outputStream, buf, strlen(buf));
+         (*outputFunc)(outputStream, " put\n", 5);
        }
       } else if ((encFormat & 0x7f) == 1) {
-       nRanges = *ptr++;
+       if (pos >= len) {
+         goto err0;
+       }
+       nRanges = file[pos++];
+       if (pos + 2 * nRanges > len) {
+         goto err0;
+       }
        nCodes = 1;
        for (i = 0; i < nRanges; ++i) {
-         c = *ptr++;
-         nLeft = *ptr++;
+         c = file[pos++];
+         nLeft = file[pos++];
          for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
-           fprintf(out, "dup %d /%s put\n",
-                   c, getString(glyphNames[nCodes], buf));
+           sprintf(buf, "dup %d /", c);
+           (*outputFunc)(outputStream, buf, strlen(buf));
+           getString(glyphNames[nCodes], buf);
+           (*outputFunc)(outputStream, buf, strlen(buf));
+           (*outputFunc)(outputStream, " put\n", 5);
            ++nCodes;
            ++c;
          }
        }
       }
       if (encFormat & 0x80) {
-       nSups = *ptr++;
+       if (pos >= len) {
+         goto err0;
+       }
+       nSups = file[pos++];
+       if (pos + nSups * 3 > len) {
+         goto err0;
+       }
        for (i = 0; i < nSups; ++i) {
-         c = *ptr++;
-         sid = getWord(ptr, 2);
-         ptr += 2;
-         fprintf(out, "dup %d /%s put\n", c, getString(sid, buf));
+         c = file[pos++];
+         sid = getWord(pos, 2);
+         pos += 2;
+         sprintf(buf, "dup %d /", c);
+         (*outputFunc)(outputStream, buf, strlen(buf));
+         getString(sid, buf);
+         (*outputFunc)(outputStream, buf, strlen(buf));
+         (*outputFunc)(outputStream, " put\n", 5);
        }
       }
+     err0:;
     }
-    fprintf(out, "readonly def\n");
+    (*outputFunc)(outputStream, "readonly def\n", 13);
   }
-  fprintf(out, "currentdict end\n");
+  (*outputFunc)(outputStream, "currentdict end\n", 16);
 
   // start the binary section
-  fprintf(out, "currentfile eexec\n");
+  (*outputFunc)(outputStream, "currentfile eexec\n", 18);
   r1 = 55665;
   line = 0;
 
@@ -486,7 +596,8 @@ void Type1CFontFile::convertToType1(FILE *outA) {
   eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n");
   eexecWrite("/ND {noaccess def} executeonly def\n");
   eexecWrite("/NP {noaccess put} executeonly def\n");
-  eexecWrite("/MinFeature {16 16} ND\n");
+  eexecWrite("/MinFeature {16 16} def\n");
+  eexecWrite("/password 5839 def\n");
   readPrivateDict(&privateDict, dict.privateOffset, dict.privateSize);
   eexecWrite(privateDict.dictData->getCString());
   defaultWidthX = privateDict.defaultWidthX;
@@ -494,41 +605,21 @@ void Type1CFontFile::convertToType1(FILE *outA) {
   nominalWidthX = privateDict.nominalWidthX;
   nominalWidthXFP = privateDict.nominalWidthXFP;
 
-  // get subrs
-  if (privateDict.subrsOffset != 0) {
-    subrsIdxPtr = (Guchar *)file + dict.privateOffset +
-                  privateDict.subrsOffset;
-    nSubrs = getIndexLen(subrsIdxPtr);
-    sprintf(eBuf, "/Subrs %d array\n", nSubrs);
-    eexecWrite(eBuf);
-    idxPtr1 = getIndexValPtr(subrsIdxPtr, 0);
-    for (i = 0; i < nSubrs; ++i) {
-      idxPtr0 = idxPtr1;
-      idxPtr1 = getIndexValPtr(subrsIdxPtr, i+1);
-      n = idxPtr1 - idxPtr0;
-#if 1 //~ Type 2 subrs are unimplemented
-      error(-1, "Unimplemented Type 2 subrs");
-#else
-      sprintf(eBuf, "dup %d %d RD ", i, n);
-      eexecWrite(eBuf);
-      eexecCvtGlyph(idxPtr0, n);
-      eexecWrite(" NP\n");
-#endif
-    }
-    eexecWrite("ND\n");
-  }
+  // set up subroutines
+  subrIdxPos = privateDict.subrsOffset;
+  i = getIndexLen(gsubrIdxPos);
+  gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+  i = getIndexLen(subrIdxPos);
+  subrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
 
   // get CharStrings
-  charStringsIdxPtr = (Guchar *)file + dict.charStrings;
-  nCharStrings = getIndexLen(charStringsIdxPtr);
+  nCharStrings = getIndexLen(dict.charStrings);
   sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings);
   eexecWrite(eBuf);
-  idxPtr1 = getIndexValPtr(charStringsIdxPtr, 0);
   for (i = 0; i < nCharStrings; ++i) {
-    idxPtr0 = idxPtr1;
-    idxPtr1 = getIndexValPtr(charStringsIdxPtr, i+1);
-    n = idxPtr1 - idxPtr0;
-    eexecCvtGlyph(getString(glyphNames[i], buf), idxPtr0, n);
+    if ((idxPos = getIndexValPos(dict.charStrings, i, &idxLen)) >= 0) {
+      eexecCvtGlyph(getString(glyphNames[i], buf), idxPos, idxLen);
+    }
   }
   eexecWrite("end\n");
   eexecWrite("end\n");
@@ -539,12 +630,12 @@ void Type1CFontFile::convertToType1(FILE *outA) {
 
   // trailer
   if (line > 0) {
-    fputc('\n', out);
+    (*outputFunc)(outputStream, "\n", 1);
   }
   for (i = 0; i < 8; ++i) {
-    fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+    (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
   }
-  fprintf(out, "cleartomark\n");
+  (*outputFunc)(outputStream, "cleartomark\n", 12);
 
   // clean up
   delete privateDict.dictData;
@@ -553,7 +644,9 @@ void Type1CFontFile::convertToType1(FILE *outA) {
   }
 }
 
-void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
+void Type1CFontFile::convertToCIDType0(char *psName,
+                                      FontFileOutputFunc outputFuncA,
+                                      void *outputStreamA) {
   Type1CTopDict dict;
   Type1CPrivateDict *privateDicts;
   GString *charStrings;
@@ -561,8 +654,8 @@ void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
   Gushort *charset;
   int *cidMap;
   Guchar *fdSelect;
-  Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
-  char buf[256];
+  int idxPos, idxLen, pos;
+  char buf[512], buf2[16];
   int nGlyphs, nCIDs, gdBytes, nFDs;
   int fdSelectFmt, nRanges, gid0, gid1, fd, offset;
   int key;
@@ -570,9 +663,10 @@ void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
   GBool isFP;
   int i, j, k, n;
 
-  out = outA;
+  outputFunc = outputFuncA;
+  outputStream = outputStreamA;
 
-  fprintf(out, "/CIDInit /ProcSet findresource begin\n");
+  (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37);
 
   // read top dict (first font only)
   readTopDict(&dict);
@@ -589,29 +683,36 @@ void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
     privateDicts[0].nominalWidthX = 0;
     privateDicts[0].nominalWidthXFP = gFalse;
   } else {
-    fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
-    nFDs = getIndexLen(fdArrayIdx);
+    if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) {
+      goto err0;
+    }
     privateDicts = (Type1CPrivateDict *)
                      gmalloc(nFDs * sizeof(Type1CPrivateDict));
-    idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
     for (i = 0; i < nFDs; ++i) {
       privateDicts[i].dictData = NULL;
-      idxPtr0 = idxPtr1;
-      idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
-      ptr = idxPtr0;
+    }
+    for (i = 0; i < nFDs; ++i) {
+      privateDicts[i].dictData = NULL;
+      if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) {
+       goto err1;
+      }
+      pos = idxPos;
       j = 0;
-      while (ptr < idxPtr1) {
-       if (*ptr <= 27 || *ptr == 31) {
-         key = *ptr++;
+      while (pos < idxPos + idxLen) {
+       if (file[pos] <= 27 || file[pos] == 31) {
+         key = file[pos++];
          if (key == 0x0c) {
-           key = (key << 8) | *ptr++;
+           if (pos >= idxPos + idxLen) {
+             goto err1;
+           }
+           key = (key << 8) | file[pos++];
          }
          if (key == 0x0012) {
            readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
          }
          j = 0;
        } else {
-         x = getNum(&ptr, &isFP);
+         x = getNum(&pos, &isFP);
          if (j < 48) {
            op[j] = x;
            fp[j++] = isFP;
@@ -630,8 +731,9 @@ void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
   }
 
   // get the glyph count
-  charStringsIdxPtr = (Guchar *)file + dict.charStrings;
-  nGlyphs = getIndexLen(charStringsIdxPtr);
+  if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) {
+    goto err1;
+  }
 
   // read the FDSelect table
   fdSelect = (Guchar *)gmalloc(nGlyphs);
@@ -640,19 +742,31 @@ void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
       fdSelect[i] = 0;
     }
   } else {
-    ptr = (Guchar *)file + dict.fdSelectOffset;
-    fdSelectFmt = *ptr++;
+    pos = dict.fdSelectOffset;
+    if (pos < 0 || pos >= len) {
+      goto err2;
+    }
+    fdSelectFmt = file[pos++];
     if (fdSelectFmt == 0) {
-      memcpy(fdSelect, ptr, nGlyphs);
+      if (pos + nGlyphs > len) {
+       goto err2;
+      }
+      memcpy(fdSelect, file + pos, nGlyphs);
     } else if (fdSelectFmt == 3) {
-      nRanges = getWord(ptr, 2);
-      ptr += 2;
-      gid0 = getWord(ptr, 2);
-      ptr += 2;
+      if (pos + 4 > len) {
+       goto err2;
+      }
+      nRanges = getWord(pos, 2);
+      pos += 2;
+      gid0 = getWord(pos, 2);
+      pos += 2;
+      if (pos + nRanges * 3 > len) {
+       goto err2;
+      }
       for (i = 1; i <= nRanges; ++i) {
-       fd = *ptr++;
-       gid1 = getWord(ptr, 2);
-       ptr += 2;
+       fd = file[pos++];
+       gid1 = getWord(pos, 2);
+       pos += 2;
        for (j = gid0; j < gid1; ++j) {
          fdSelect[j] = fd;
        }
@@ -682,23 +796,30 @@ void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
     cidMap[charset[i]] = i;
   }
 
+  // set up global subroutines
+  i = getIndexLen(gsubrIdxPos);
+  gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+
   // build the charstrings
   charStrings = new GString();
   charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int));
   for (i = 0; i < nCIDs; ++i) {
     charStringOffsets[i] = charStrings->getLength();
     if (cidMap[i] >= 0) {
-      idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i]);
-      idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i]+1);
-      n = idxPtr1 - idxPtr0;
-      j = fdSelect[cidMap[i]];
-      defaultWidthX = privateDicts[j].defaultWidthX;
-      defaultWidthXFP = privateDicts[j].defaultWidthXFP;
-      nominalWidthX = privateDicts[j].nominalWidthX;
-      nominalWidthXFP = privateDicts[j].nominalWidthXFP;
-      cvtGlyph(idxPtr0, n);
-      charStrings->append(charBuf);
-      delete charBuf;
+      if ((idxPos = getIndexValPos(dict.charStrings,
+                                  cidMap[i], &idxLen)) >= 0) {
+       j = fdSelect[cidMap[i]];
+       defaultWidthX = privateDicts[j].defaultWidthX;
+       defaultWidthXFP = privateDicts[j].defaultWidthXFP;
+       nominalWidthX = privateDicts[j].nominalWidthX;
+       nominalWidthXFP = privateDicts[j].nominalWidthXFP;
+       subrIdxPos = privateDicts[j].subrsOffset;
+       k = getIndexLen(subrIdxPos);
+       subrBias = (k < 1240) ? 107 : (k < 33900) ? 1131 : 32768;
+       cvtGlyph(idxPos, idxLen, gTrue);
+       charStrings->append(charBuf);
+       delete charBuf;
+      }
     }
   }
   charStringOffsets[nCIDs] = charStrings->getLength();
@@ -719,65 +840,82 @@ void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
   }
 
   // begin the font dictionary
-  fprintf(out, "20 dict begin\n");
-  fprintf(out, "/CIDFontName /%s def\n", psName);
-  fprintf(out, "/CIDFontType 0 def\n");
-  fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
+  (*outputFunc)(outputStream, "20 dict begin\n", 14);
+  (*outputFunc)(outputStream, "/CIDFontName /", 14);
+  (*outputFunc)(outputStream, psName, strlen(psName));
+  (*outputFunc)(outputStream, " def\n", 5);
+  (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19);
+  (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
   if (dict.registry > 0 && dict.ordering > 0) {
-    fprintf(out, "  /Registry (%s) def\n", getString(dict.registry, buf));
-    fprintf(out, "  /Ordering (%s) def\n", getString(dict.ordering, buf));
+    getString(dict.registry, buf);
+    (*outputFunc)(outputStream, "  /Registry (", 13);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, ") def\n", 6);
+    getString(dict.ordering, buf);
+    (*outputFunc)(outputStream, "  /Ordering (", 13);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, ") def\n", 6);
   } else {
-    fprintf(out, "  /Registry (Adobe) def\n");
-    fprintf(out, "  /Ordering (Identity) def\n");
+    (*outputFunc)(outputStream, "  /Registry (Adobe) def\n", 24);
+    (*outputFunc)(outputStream, "  /Ordering (Identity) def\n", 27);
   }
-  fprintf(out, "  /Supplement %d def\n", dict.supplement);
-  fprintf(out, "end def\n");
-  fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
+  sprintf(buf, "  /Supplement %d def\n", dict.supplement);
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  (*outputFunc)(outputStream, "end def\n", 8);
+  sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n",
          dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
          dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
-  fprintf(out, "/FontBBox [%g %g %g %g] def\n",
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  sprintf(buf, "/FontBBox [%g %g %g %g] def\n",
          dict.fontBBox[0], dict.fontBBox[1],
          dict.fontBBox[2], dict.fontBBox[3]);
-  fprintf(out, "/FontInfo 1 dict dup begin\n");
-  fprintf(out, "  /FSType 8 def\n");
-  fprintf(out, "end def\n");
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27);
+  (*outputFunc)(outputStream, "  /FSType 8 def\n", 16);
+  (*outputFunc)(outputStream, "end def\n", 8);
 
   // CIDFont-specific entries
-  fprintf(out, "/CIDCount %d def\n", nCIDs);
-  fprintf(out, "/FDBytes 1 def\n");
-  fprintf(out, "/GDBytes %d def\n", gdBytes);
-  fprintf(out, "/CIDMapOffset 0 def\n");
+  sprintf(buf, "/CIDCount %d def\n", nCIDs);
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15);
+  sprintf(buf, "/GDBytes %d def\n", gdBytes);
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20);
   if (dict.paintType != 0) {
-    fprintf(out, "/PaintType %d def\n", dict.paintType);
-    fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+    sprintf(buf, "/PaintType %d def\n", dict.paintType);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth);
+    (*outputFunc)(outputStream, buf, strlen(buf));
   }
 
   // FDArray entry
-  fprintf(out, "/FDArray %d array\n", nFDs);
+  sprintf(buf, "/FDArray %d array\n", nFDs);
+  (*outputFunc)(outputStream, buf, strlen(buf));
   for (i = 0; i < nFDs; ++i) {
-    fprintf(out, "dup %d 10 dict begin\n", i);
-    fprintf(out, "/FontType 1 def\n");
-    fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
-    fprintf(out, "/PaintType %d def\n", dict.paintType);
-    fprintf(out, "/Private 32 dict begin\n");
-    fwrite(privateDicts[i].dictData->getCString(), 1,
-          privateDicts[i].dictData->getLength(), out);
-    fprintf(out, "currentdict end def\n");
-    fprintf(out, "currentdict end put\n");
-  }
-  fprintf(out, "def\n");
-
-  //~ need to deal with subrs
-  
+    sprintf(buf, "dup %d 10 dict begin\n", i);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+    (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+    sprintf(buf, "/PaintType %d def\n", dict.paintType);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23);
+    (*outputFunc)(outputStream, privateDicts[i].dictData->getCString(),
+                 privateDicts[i].dictData->getLength());
+    (*outputFunc)(outputStream, "currentdict end def\n", 20);
+    (*outputFunc)(outputStream, "currentdict end put\n", 20);
+  }
+  (*outputFunc)(outputStream, "def\n", 4);
+
   // start the binary section
   offset = (nCIDs + 1) * (1 + gdBytes);
-  fprintf(out, "(Hex) %d StartData\n",
+  sprintf(buf, "(Hex) %d StartData\n",
          offset + charStrings->getLength());
+  (*outputFunc)(outputStream, buf, strlen(buf));
 
   // write the charstring offset (CIDMap) table
   for (i = 0; i <= nCIDs; i += 6) {
     for (j = 0; j < 6 && i+j <= nCIDs; ++j) {
-      if (cidMap[i+j] >= 0) {
+      if (i+j < nCIDs && cidMap[i+j] >= 0) {
        buf[0] = (char)fdSelect[cidMap[i+j]];
       } else {
        buf[0] = (char)0;
@@ -788,52 +926,62 @@ void Type1CFontFile::convertToCIDType0(char *psName, FILE *outA) {
        n >>= 8;
       }
       for (k = 0; k <= gdBytes; ++k) {
-       fprintf(out, "%02x", buf[k] & 0xff);
+       sprintf(buf2, "%02x", buf[k] & 0xff);
+       (*outputFunc)(outputStream, buf2, 2);
       }
     }
-    fputc('\n', out);
+    (*outputFunc)(outputStream, "\n", 1);
   }
 
   // write the charstring data
   n = charStrings->getLength();
   for (i = 0; i < n; i += 32) {
     for (j = 0; j < 32 && i+j < n; ++j) {
-      fprintf(out, "%02x", charStrings->getChar(i+j) & 0xff);
+      sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff);
+      (*outputFunc)(outputStream, buf, strlen(buf));
     }
     if (i + 32 >= n) {
-      fputc('>', out);
+      (*outputFunc)(outputStream, ">", 1);
     }
-    fputc('\n', out);
+    (*outputFunc)(outputStream, "\n", 1);
   }
 
-  for (i = 0; i < nFDs; ++i) {
-    delete privateDicts[i].dictData;
-  }
-  gfree(privateDicts);
-  gfree(cidMap);
-  gfree(charset);
   gfree(charStringOffsets);
   delete charStrings;
+  gfree(cidMap);
+  gfree(charset);
+ err2:
   gfree(fdSelect);
+ err1:
+  for (i = 0; i < nFDs; ++i) {
+    if (privateDicts[i].dictData) {
+      delete privateDicts[i].dictData;
+    }
+  }
+  gfree(privateDicts);
+ err0:;
 }
 
-void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
+void Type1CFontFile::convertToType0(char *psName,
+                                   FontFileOutputFunc outputFuncA,
+                                   void *outputStreamA) {
   Type1CTopDict dict;
   Type1CPrivateDict *privateDicts;
   Gushort *charset;
   int *cidMap;
   Guchar *fdSelect;
-  Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
-  char buf[256];
+  int idxPos, idxLen, pos;
+  char buf[512];
   char eBuf[256];
   int nGlyphs, nCIDs, nFDs;
   int fdSelectFmt, nRanges, gid0, gid1, fd;
   int key;
   double x;
   GBool isFP;
-  int i, j, n;
+  int i, j;
 
-  out = outA;
+  outputFunc = outputFuncA;
+  outputStream = outputStreamA;
 
   // read top dict (first font only)
   readTopDict(&dict);
@@ -850,29 +998,36 @@ void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
     privateDicts[0].nominalWidthX = 0;
     privateDicts[0].nominalWidthXFP = gFalse;
   } else {
-    fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
-    nFDs = getIndexLen(fdArrayIdx);
+    if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) {
+      goto err0;
+    }
     privateDicts = (Type1CPrivateDict *)
                      gmalloc(nFDs * sizeof(Type1CPrivateDict));
-    idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
     for (i = 0; i < nFDs; ++i) {
       privateDicts[i].dictData = NULL;
-      idxPtr0 = idxPtr1;
-      idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
-      ptr = idxPtr0;
+    }
+    for (i = 0; i < nFDs; ++i) {
+      privateDicts[i].dictData = NULL;
+      if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) {
+       goto err1;
+      }
+      pos = idxPos;
       j = 0;
-      while (ptr < idxPtr1) {
-       if (*ptr <= 27 || *ptr == 31) {
-         key = *ptr++;
+      while (pos < idxPos + idxLen) {
+       if (file[pos] <= 27 || file[pos] == 31) {
+         key = file[pos++];
          if (key == 0x0c) {
-           key = (key << 8) | *ptr++;
+           if (pos >= idxPos + idxLen) {
+             goto err1;
+           }
+           key = (key << 8) | file[pos++];
          }
          if (key == 0x0012) {
            readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
          }
          j = 0;
        } else {
-         x = getNum(&ptr, &isFP);
+         x = getNum(&pos, &isFP);
          if (j < 48) {
            op[j] = x;
            fp[j++] = isFP;
@@ -891,8 +1046,9 @@ void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
   }
 
   // get the glyph count
-  charStringsIdxPtr = (Guchar *)file + dict.charStrings;
-  nGlyphs = getIndexLen(charStringsIdxPtr);
+  if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) {
+    goto err1;
+  }
 
   // read the FDSelect table
   fdSelect = (Guchar *)gmalloc(nGlyphs);
@@ -901,19 +1057,31 @@ void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
       fdSelect[i] = 0;
     }
   } else {
-    ptr = (Guchar *)file + dict.fdSelectOffset;
-    fdSelectFmt = *ptr++;
+    pos = dict.fdSelectOffset;
+    if (pos < 0 || pos >= len) {
+      goto err2;
+    }
+    fdSelectFmt = file[pos++];
     if (fdSelectFmt == 0) {
-      memcpy(fdSelect, ptr, nGlyphs);
+      if (pos + nGlyphs > len) {
+       goto err2;
+      }
+      memcpy(fdSelect, file + pos, nGlyphs);
     } else if (fdSelectFmt == 3) {
-      nRanges = getWord(ptr, 2);
-      ptr += 2;
-      gid0 = getWord(ptr, 2);
-      ptr += 2;
+      if (pos + 4 > len) {
+       goto err2;
+      }
+      nRanges = getWord(pos, 2);
+      pos += 2;
+      gid0 = getWord(pos, 2);
+      pos += 2;
+      if (pos + nRanges * 3 > len) {
+       goto err2;
+      }
       for (i = 1; i <= nRanges; ++i) {
-       fd = *ptr++;
-       gid1 = getWord(ptr, 2);
-       ptr += 2;
+       fd = file[pos++];
+       gid1 = getWord(pos, 2);
+       pos += 2;
        for (j = gid0; j < gid1; ++j) {
          fdSelect[j] = fd;
        }
@@ -943,6 +1111,10 @@ void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
     cidMap[charset[i]] = i;
   }
 
+  // set up global subroutines
+  i = getIndexLen(gsubrIdxPos);
+  gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+
   // write the descendant Type 1 fonts
   for (i = 0; i < nCIDs; i += 256) {
 
@@ -958,28 +1130,40 @@ void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
     }
 
     // font dictionary (unencrypted section)
-    fprintf(out, "16 dict begin\n");
-    fprintf(out, "/FontName /%s_%02x def\n", psName, i >> 8);
-    fprintf(out, "/FontType 1 def\n");
-    fprintf(out, "/FontMatrix [%g %g %g %g %g %g] def\n",
+    (*outputFunc)(outputStream, "16 dict begin\n", 14);
+    (*outputFunc)(outputStream, "/FontName /", 11);
+    (*outputFunc)(outputStream, psName, strlen(psName));
+    sprintf(buf, "_%02x def\n", i >> 8);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, "/FontType 1 def\n", 16);
+    sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n",
            dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2],
            dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]);
-    fprintf(out, "/FontBBox [%g %g %g %g] def\n",
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    sprintf(buf, "/FontBBox [%g %g %g %g] def\n",
            dict.fontBBox[0], dict.fontBBox[1],
            dict.fontBBox[2], dict.fontBBox[3]);
-    fprintf(out, "/PaintType %d def\n", dict.paintType);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    sprintf(buf, "/PaintType %d def\n", dict.paintType);
+    (*outputFunc)(outputStream, buf, strlen(buf));
     if (dict.paintType != 0) {
-      fprintf(out, "/StrokeWidth %g def\n", dict.strokeWidth);
+      sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth);
+      (*outputFunc)(outputStream, buf, strlen(buf));
     }
-    fprintf(out, "/Encoding 256 array\n");
+    (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
     for (j = 0; j < 256 && i+j < nCIDs; ++j) {
-      fprintf(out, "dup %d /c%02x put\n", j, j);
+      sprintf(buf, "dup %d /c%02x put\n", j, j);
+      (*outputFunc)(outputStream, buf, strlen(buf));
+    }
+    if (j < 256) {
+      sprintf(buf, "%d 1 255 { 1 index exch /.notdef put } for\n", j);
+      (*outputFunc)(outputStream, buf, strlen(buf));
     }
-    fprintf(out, "readonly def\n");
-    fprintf(out, "currentdict end\n");
+    (*outputFunc)(outputStream, "readonly def\n", 13);
+    (*outputFunc)(outputStream, "currentdict end\n", 16);
 
     // start the binary section
-    fprintf(out, "currentfile eexec\n");
+    (*outputFunc)(outputStream, "currentfile eexec\n", 18);
     r1 = 55665;
     line = 0;
 
@@ -989,31 +1173,36 @@ void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
     eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n");
     eexecWrite("/ND {noaccess def} executeonly def\n");
     eexecWrite("/NP {noaccess put} executeonly def\n");
-    eexecWrite("/MinFeature {16 16} ND\n");
+    eexecWrite("/MinFeature {16 16} def\n");
+    eexecWrite("/password 5839 def\n");
     eexecWrite(privateDicts[fd].dictData->getCString());
     defaultWidthX = privateDicts[fd].defaultWidthX;
     defaultWidthXFP = privateDicts[fd].defaultWidthXFP;
     nominalWidthX = privateDicts[fd].nominalWidthX;
     nominalWidthXFP = privateDicts[fd].nominalWidthXFP;
 
+    // set up the subroutines
+    subrIdxPos = privateDicts[fd].subrsOffset;
+    j = getIndexLen(subrIdxPos);
+    subrBias = (j < 1240) ? 107 : (j < 33900) ? 1131 : 32768;
+
     // start the CharStrings
     sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n");
     eexecWrite(eBuf);
 
     // write the .notdef CharString
-    idxPtr0 = getIndexValPtr(charStringsIdxPtr, 0);
-    idxPtr1 = getIndexValPtr(charStringsIdxPtr, 1);
-    n = idxPtr1 - idxPtr0;
-    eexecCvtGlyph(".notdef", idxPtr0, n);
+    if ((idxPos = getIndexValPos(dict.charStrings, 0, &idxLen)) >= 0) {
+      eexecCvtGlyph(".notdef", idxPos, idxLen);
+    }
 
     // write the CharStrings
     for (j = 0; j < 256 && i+j < nCIDs; ++j) {
       if (cidMap[i+j] >= 0) {
-       idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]);
-       idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]+1);
-       n = idxPtr1 - idxPtr0;
-       sprintf(buf, "c%02x", j);
-       eexecCvtGlyph(buf, idxPtr0, n);
+       if ((idxPos = getIndexValPos(dict.charStrings,
+                                    cidMap[i+j], &idxLen)) >= 0) {
+         sprintf(buf, "c%02x", j);
+         eexecCvtGlyph(buf, idxPos, idxLen);
+       }
       }
     }
     eexecWrite("end\n");
@@ -1025,51 +1214,60 @@ void Type1CFontFile::convertToType0(char *psName, FILE *outA) {
 
     // trailer
     if (line > 0) {
-      fputc('\n', out);
+      (*outputFunc)(outputStream, "\n", 1);
     }
     for (j = 0; j < 8; ++j) {
-      fprintf(out, "0000000000000000000000000000000000000000000000000000000000000000\n");
+      (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65);
     }
-    fprintf(out, "cleartomark\n");
+    (*outputFunc)(outputStream, "cleartomark\n", 12);
   }
 
   // write the Type 0 parent font
-  fprintf(out, "16 dict begin\n");
-  fprintf(out, "/FontName /%s def\n", psName);
-  fprintf(out, "/FontType 0 def\n");
-  fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
-  fprintf(out, "/FMapType 2 def\n");
-  fprintf(out, "/Encoding [\n");
+  (*outputFunc)(outputStream, "16 dict begin\n", 14);
+  (*outputFunc)(outputStream, "/FontName /", 11);
+  (*outputFunc)(outputStream, psName, strlen(psName));
+  (*outputFunc)(outputStream, " def\n", 5);
+  (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
+  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+  (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
+  (*outputFunc)(outputStream, "/Encoding [\n", 12);
   for (i = 0; i < nCIDs; i += 256) {
-    fprintf(out, "%d\n", i >> 8);
+    sprintf(buf, "%d\n", i >> 8);
+    (*outputFunc)(outputStream, buf, strlen(buf));
   }
-  fprintf(out, "] def\n");
-  fprintf(out, "/FDepVector [\n");
+  (*outputFunc)(outputStream, "] def\n", 6);
+  (*outputFunc)(outputStream, "/FDepVector [\n", 14);
   for (i = 0; i < nCIDs; i += 256) {
-    fprintf(out, "/%s_%02x findfont\n", psName, i >> 8);
+    (*outputFunc)(outputStream, "/", 1);
+    (*outputFunc)(outputStream, psName, strlen(psName));
+    sprintf(buf, "_%02x findfont\n", i >> 8);
+    (*outputFunc)(outputStream, buf, strlen(buf));
   }
-  fprintf(out, "] def\n");
-  fprintf(out, "FontName currentdict end definefont pop\n");
+  (*outputFunc)(outputStream, "] def\n", 6);
+  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
 
   // clean up
-  for (i = 0; i < nFDs; ++i) {
-    delete privateDicts[i].dictData;
-  }
-  gfree(privateDicts);
   gfree(cidMap);
   gfree(charset);
+ err2:
   gfree(fdSelect);
+ err1:
+  for (i = 0; i < nFDs; ++i) {
+    if (privateDicts[i].dictData) {
+      delete privateDicts[i].dictData;
+    }
+  }
+  gfree(privateDicts);
+ err0:;
 }
 
 void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
-  Guchar *idxPtr0, *idxPtr1, *ptr;
+  int idxPos, idxLen, pos;
   double x;
   GBool isFP;
   int key;
   int i;
 
-  idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
-  idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
   dict->version = 0;
   dict->notice = 0;
   dict->copyright = 0;
@@ -1104,13 +1302,19 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
   dict->supplement = 0;
   dict->fdArrayOffset = 0;
   dict->fdSelectOffset = 0;
+  if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) {
+    return;
+  }
   i = 0;
-  ptr = idxPtr0;
-  while (ptr < idxPtr1) {
-    if (*ptr <= 27 || *ptr == 31) {
-      key = *ptr++;
+  pos = idxPos;
+  while (pos < idxPos + idxLen) {
+    if (file[pos] <= 27 || file[pos] == 31) {
+      key = file[pos++];
       if (key == 0x0c) {
-       key = (key << 8) | *ptr++;
+       if (pos >= idxPos + idxLen) {
+         break;
+       }
+       key = (key << 8) | file[pos++];
       }
       switch (key) {
       case 0x0000: dict->version = (int)op[0]; break;
@@ -1150,7 +1354,7 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
       }
       i = 0;
     } else {
-      x = getNum(&ptr, &isFP);
+      x = getNum(&pos, &isFP);
       if (i < 48) {
        op[i] = x;
        fp[i++] = isFP;
@@ -1161,7 +1365,7 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
 
 void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
                                     int offset, int size) {
-  Guchar *idxPtr0, *idxPtr1, *ptr;
+  int pos;
   char eBuf[256];
   int key;
   double x;
@@ -1174,15 +1378,19 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
   privateDict->defaultWidthXFP = gFalse;
   privateDict->nominalWidthX = 0;
   privateDict->nominalWidthXFP = gFalse;
-  idxPtr0 = (Guchar *)file + offset;
-  idxPtr1 = idxPtr0 + size;
-  ptr = idxPtr0;
+  if (offset < 0 || offset + size > len) {
+    return;
+  }
+  pos = offset;
   i = 0;
-  while (ptr < idxPtr1) {
-    if (*ptr <= 27 || *ptr == 31) {
-      key = *ptr++;
+  while (pos < offset + size) {
+    if (file[pos] <= 27 || file[pos] == 31) {
+      key = file[pos++];
       if (key == 0x0c) {
-       key = (key << 8) | *ptr++;
+       if (pos >= offset + size) {
+         break;
+       }
+       key = (key << 8) | file[pos++];
       }
       switch (key) {
       case 0x0006:
@@ -1249,7 +1457,7 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
        error(-1, "Got Type 1C InitialRandomSeed");
        break;
       case 0x0013:
-       privateDict->subrsOffset = (int)op[0];
+       privateDict->subrsOffset = offset + (int)op[0];
        break;
       case 0x0014:
        privateDict->defaultWidthX = op[0];
@@ -1265,7 +1473,7 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
       }
       i = 0;
     } else {
-      x = getNum(&ptr, &isFP);
+      x = getNum(&pos, &isFP);
       if (i < 48) {
        op[i] = x;
        fp[i++] = isFP;
@@ -1276,7 +1484,7 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
 
 Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
   Gushort *glyphNames;
-  Guchar *ptr;
+  int pos;
   int charsetFormat, c;
   int nLeft, i, j;
 
@@ -1288,20 +1496,31 @@ Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
     glyphNames = type1CExpertSubsetCharset;
   } else {
     glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
-    glyphNames[0] = 0;
-    ptr = (Guchar *)file + charset;
-    charsetFormat = *ptr++;
+    for (i = 0; i < nGlyphs; ++i) {
+      glyphNames[i] = 0;
+    }
+    pos = charset;
+    if (pos < 0 || pos >= len) {
+      goto err0;
+    }
+    charsetFormat = file[pos++];
     if (charsetFormat == 0) {
+      if (pos + (nGlyphs - 1) * 2 >= len) {
+       goto err0;
+      }
       for (i = 1; i < nGlyphs; ++i) {
-       glyphNames[i] = getWord(ptr, 2);
-       ptr += 2;
+       glyphNames[i] = getWord(pos, 2);
+       pos += 2;
       }
     } else if (charsetFormat == 1) {
       i = 1;
       while (i < nGlyphs) {
-       c = getWord(ptr, 2);
-       ptr += 2;
-       nLeft = *ptr++;
+       if (pos + 3 > len) {
+         goto err0;
+       }
+       c = getWord(pos, 2);
+       pos += 2;
+       nLeft = file[pos++];
        for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
          glyphNames[i++] = c++;
        }
@@ -1309,16 +1528,20 @@ Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
     } else if (charsetFormat == 2) {
       i = 1;
       while (i < nGlyphs) {
-       c = getWord(ptr, 2);
-       ptr += 2;
-       nLeft = getWord(ptr, 2);
-       ptr += 2;
+       if (pos + 4 > len) {
+         goto err0;
+       }
+       c = getWord(pos, 2);
+       pos += 2;
+       nLeft = getWord(pos, 2);
+       pos += 2;
        for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
          glyphNames[i++] = c++;
        }
       }
     }
   }
+ err0:
   return glyphNames;
 }
 
@@ -1329,20 +1552,20 @@ void Type1CFontFile::eexecWrite(char *s) {
   for (p = (Guchar *)s; *p; ++p) {
     x = *p ^ (r1 >> 8);
     r1 = (x + r1) * 52845 + 22719;
-    fputc(hexChars[x >> 4], out);
-    fputc(hexChars[x & 0x0f], out);
+    (*outputFunc)(outputStream, &hexChars[x >> 4], 1);
+    (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1);
     line += 2;
     if (line == 64) {
-      fputc('\n', out);
+      (*outputFunc)(outputStream, "\n", 1);
       line = 0;
     }
   }
 }
 
-void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) {
+void Type1CFontFile::eexecCvtGlyph(char *glyphName, int pos, int n) {
   char eBuf[256];
 
-  cvtGlyph(s, n);
+  cvtGlyph(pos, n, gTrue);
   sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength());
   eexecWrite(eBuf);
   eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
@@ -1350,28 +1573,37 @@ void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) {
   delete charBuf;
 }
 
-void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
-  int nHints;
+void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) {
   int x;
-  GBool first = gTrue;
+  int subrPos, subrLen;
   double d, dx, dy;
   GBool dFP;
   Gushort r2;
   Guchar byte;
   int i, k;
 
-  charBuf = new GString();
-  charBuf->append((char)73);
-  charBuf->append((char)58);
-  charBuf->append((char)147);
-  charBuf->append((char)134);
+  if (pos < 0 || pos + n > len) {
+    return;
+  }
 
-  i = 0;
-  nOps = 0;
-  nHints = 0;
-  while (i < n) {
-    if (s[i] == 12) {
-      switch (s[i+1]) {
+  if (top) {
+    charBuf = new GString();
+    charBuf->append((char)73);
+    charBuf->append((char)58);
+    charBuf->append((char)147);
+    charBuf->append((char)134);
+    nOps = 0;
+    nHints = 0;
+    firstOp = gTrue;
+  }
+
+  i = pos;
+  while (i < pos + n) {
+    if (file[i] == 12) {
+      if (i + 2 > pos + n) {
+       break;
+      }
+      switch (file[i+1]) {
       case 0:                  // dotsection (should be Type 1 only?)
        // ignored
        break;
@@ -1480,19 +1712,19 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
       case 28:                 // exch
       case 29:                 // index
       case 30:                 // roll
-       error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]);
+       error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]);
        break;
       default:
-       error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]);
+       error(-1, "Illegal Type 2 charstring op: 12.%d", file[i+1]);
        break;
       }
       i += 2;
       nOps = 0;
-    } else if (s[i] == 19) {   // hintmask
+    } else if (file[i] == 19) {        // hintmask
       // ignored
-      if (first) {
-       cvtGlyphWidth(nOps == 1);
-       first = gFalse;
+      if (firstOp) {
+       cvtGlyphWidth(nOps & 1);
+       firstOp = gFalse;
       }
       if (nOps > 0) {
        if (nOps & 1) {
@@ -1503,11 +1735,11 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
       }
       i += 1 + ((nHints + 7) >> 3);
       nOps = 0;
-    } else if (s[i] == 20) {   // cntrmask
+    } else if (file[i] == 20) {        // cntrmask
       // ignored
-      if (first) {
-       cvtGlyphWidth(nOps == 1);
-       first = gFalse;
+      if (firstOp) {
+       cvtGlyphWidth(nOps & 1);
+       firstOp = gFalse;
       }
       if (nOps > 0) {
        if (nOps & 1) {
@@ -1518,8 +1750,11 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
       }
       i += 1 + ((nHints + 7) >> 3);
       nOps = 0;
-    } else if (s[i] == 28) {
-      x = (s[i+1] << 8) + s[i+2];
+    } else if (file[i] == 28) {
+      if (i + 3 > len) {
+       break;
+      }
+      x = (file[i+1] << 8) + file[i+2];
       if (x & 0x8000) {
        x |= -1 << 15;
       }
@@ -1528,12 +1763,39 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        op[nOps++] = x;
       }
       i += 3;
-    } else if (s[i] <= 31) {
-      switch (s[i]) {
+    } else if (file[i] == 10) {        // callsubr
+      if (nOps >= 1) {
+       k = subrBias + (int)op[nOps - 1];
+       --nOps;
+       if ((subrPos = getIndexValPos(subrIdxPos, k, &subrLen)) >= 0) {
+         cvtGlyph(subrPos, subrLen, gFalse);
+       }
+      } else {
+       error(-1, "Too few args to Type 2 callsubr");
+      }
+      // don't clear the stack
+      ++i;
+    } else if (file[i] == 29) {        // callgsubr
+      if (nOps >= 1) {
+       k = gsubrBias + (int)op[nOps - 1];
+       --nOps;
+       if ((subrPos = getIndexValPos(gsubrIdxPos, k, &subrLen)) >= 0) {
+         cvtGlyph(subrPos, subrLen, gFalse);
+       }
+      } else {
+       error(-1, "Too few args to Type 2 callgsubr");
+      }
+      // don't clear the stack
+      ++i;
+    } else if (file[i] == 11) {        // return
+      // don't clear the stack
+      ++i;
+    } else if (file[i] <= 31) {
+      switch (file[i]) {
       case 4:                  // vmoveto
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps == 2);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps != 1) {
          error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
@@ -1584,9 +1846,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        }
        break;
       case 14:                 // endchar / seac
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps == 1 || nOps == 5);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps == 4) {
          eexecDumpNum(0, 0);
@@ -1602,9 +1864,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        }
        break;
       case 21:                 // rmoveto
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps == 3);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps != 2) {
          error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
@@ -1614,9 +1876,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        eexecDumpOp1(21);
        break;
       case 22:                 // hmoveto
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps == 2);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps != 1) {
          error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
@@ -1787,9 +2049,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        }
        break;
       case 1:                  // hstem
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps & 1);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps & 1) {
          error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
@@ -1815,9 +2077,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        nHints += nOps / 2;
        break;
       case 3:                  // vstem
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps & 1);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps & 1) {
          error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
@@ -1842,11 +2104,18 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        }
        nHints += nOps / 2;
        break;
+      case 15:                 // (obsolete)
+       // this op is ignored, but we need the glyph width
+       if (firstOp) {
+         cvtGlyphWidth(nOps > 0);
+         firstOp = gFalse;
+       }
+       break;
       case 18:                 // hstemhm
        // ignored
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps & 1);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps & 1) {
          error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
@@ -1855,49 +2124,56 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        break;
       case 23:                 // vstemhm
        // ignored
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps & 1);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps & 1) {
          error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
        }
        nHints += nOps / 2;
        break;
-      case 10:                 // callsubr
-      case 11:                 // return
       case 16:                 // blend
-      case 29:                 // callgsubr
-       error(-1, "Unimplemented Type 2 charstring op: %d", s[i]);
+       error(-1, "Unimplemented Type 2 charstring op: %d", file[i]);
        break;
       default:
-       error(-1, "Illegal Type 2 charstring op: %d", s[i]);
+       error(-1, "Illegal Type 2 charstring op: %d", file[i]);
        break;
       }
       ++i;
       nOps = 0;
-    } else if (s[i] <= 246) {
+    } else if (file[i] <= 246) {
       if (nOps < 48) {
        fp[nOps] = gFalse;
-       op[nOps++] = (int)s[i] - 139;
+       op[nOps++] = (int)file[i] - 139;
       }
       ++i;
-    } else if (s[i] <= 250) {
+    } else if (file[i] <= 250) {
+      if (i + 2 > len) {
+       break;
+      }
       if (nOps < 48) {
        fp[nOps] = gFalse;
-       op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108;
+       op[nOps++] = (((int)file[i] - 247) << 8) + (int)file[i+1] + 108;
       }
       i += 2;
-    } else if (s[i] <= 254) {
+    } else if (file[i] <= 254) {
+      if (i + 2 > len) {
+       break;
+      }
       if (nOps < 48) {
        fp[nOps] = gFalse;
-       op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108;
+       op[nOps++] = -(((int)file[i] - 251) << 8) - (int)file[i+1] - 108;
       }
       i += 2;
     } else {
-      x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4];
-      if (x & 0x80000000)
+      if (i + 5 > len) {
+       break;
+      }
+      x = (file[i+1] << 24) | (file[i+2] << 16) | (file[i+3] << 8) | file[i+4];
+      if (x & 0x80000000) {
        x |= -1 << 31;
+      }
       if (nOps < 48) {
        fp[nOps] = gTrue;
        op[nOps++] = (double)x / 65536.0;
@@ -1907,11 +2183,13 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
   }
 
   // charstring encryption
-  r2 = 4330;
-  for (i = 0; i < charBuf->getLength(); ++i) {
-    byte = charBuf->getChar(i) ^ (r2 >> 8);
-    charBuf->setChar(i, byte);
-    r2 = (byte + r2) * 52845 + 22719;
+  if (top) {
+    r2 = 4330;
+    for (i = 0; i < charBuf->getLength(); ++i) {
+      byte = charBuf->getChar(i) ^ (r2 >> 8);
+      charBuf->setChar(i, byte);
+      r2 = (byte + r2) * 52845 + 22719;
+    }
   }
 }
 
@@ -2005,11 +2283,11 @@ void Type1CFontFile::eexecWriteCharstring(Guchar *s, int n) {
   for (i = 0; i < n; ++i) {
     x = s[i] ^ (r1 >> 8);
     r1 = (x + r1) * 52845 + 22719;
-    fputc(hexChars[x >> 4], out);
-    fputc(hexChars[x & 0x0f], out);
+    (*outputFunc)(outputStream, &hexChars[x >> 4], 1);
+    (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1);
     line += 2;
     if (line == 64) {
-      fputc('\n', out);
+      (*outputFunc)(outputStream, "\n", 1);
       line = 0;
     }
   }
@@ -2046,42 +2324,71 @@ void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA,
   sprintf(buf, "] def\n");
 }
 
-int Type1CFontFile::getIndexLen(Guchar *indexPtr) {
-  return (int)getWord(indexPtr, 2);
+int Type1CFontFile::getIndexLen(int indexPos) {
+  if (indexPos + 2 > len) {
+    return -1;
+  }
+  return (int)getWord(indexPos, 2);
 }
 
-Guchar *Type1CFontFile::getIndexValPtr(Guchar *indexPtr, int i) {
-  int n, offSize;
-  Guchar *idxStartPtr;
+int Type1CFontFile::getIndexValPos(int indexPos, int i, int *valLen) {
+  int n, offSize, idxStartPos;
+  int pos0, pos1;
 
-  n = (int)getWord(indexPtr, 2);
-  offSize = indexPtr[2];
-  idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
-  return idxStartPtr + getWord(indexPtr + 3 + i * offSize, offSize);
+  if (indexPos < 0 || indexPos + 3 > len) {
+    return -1;
+  }
+  n = (int)getWord(indexPos, 2);
+  if (i >= n) {
+    return -1;
+  }
+  offSize = file[indexPos + 2];
+  if (offSize < 1 || offSize > 4) {
+    return -1;
+  }
+  idxStartPos = indexPos + 3 + (n + 1) * offSize - 1;
+  if (idxStartPos >= len) {
+    return -1;
+  }
+  pos0 = idxStartPos + getWord(indexPos + 3 + i * offSize, offSize);
+  pos1 = idxStartPos + getWord(indexPos + 3 + (i + 1) * offSize, offSize);
+  if (pos0 < 0 || pos0 >= len || pos1 < pos0 || pos1 > len) {
+    return -1;
+  }
+  *valLen = pos1 - pos0;
+  return pos0;
 }
 
-Guchar *Type1CFontFile::getIndexEnd(Guchar *indexPtr) {
-  int n, offSize;
-  Guchar *idxStartPtr;
+int Type1CFontFile::getIndexEnd(int indexPos) {
+  int n, offSize, idxStartPos;
 
-  n = (int)getWord(indexPtr, 2);
-  offSize = indexPtr[2];
-  idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
-  return idxStartPtr + getWord(indexPtr + 3 + n * offSize, offSize);
+  if (indexPos < 0 || indexPos + 3 > len) {
+    return -1;
+  }
+  n = (int)getWord(indexPos, 2);
+  offSize = file[indexPos + 2];
+  idxStartPos = indexPos + 3 + (n + 1) * offSize - 1;
+  if (idxStartPos >= len) {
+    return -1;
+  }
+  return idxStartPos + getWord(indexPos + 3 + n * offSize, offSize);
 }
 
-Guint Type1CFontFile::getWord(Guchar *ptr, int size) {
+Guint Type1CFontFile::getWord(int pos, int size) {
   Guint x;
   int i;
 
+  if (pos < 0 || pos + size > len) {
+    return 0;
+  }
   x = 0;
   for (i = 0; i < size; ++i) {
-    x = (x << 8) + *ptr++;
+    x = (x << 8) + file[pos + i];
   }
   return x;
 }
 
-double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
+double Type1CFontFile::getNum(int *pos, GBool *isFP) {
   static char nybChars[16] = "0123456789.ee -";
   int b0, b, nyb0, nyb1;
   double x;
@@ -2090,20 +2397,31 @@ double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
 
   x = 0;
   *isFP = gFalse;
-  b0 = (*ptr)[0];
+  if (*pos >= len) {
+    return 0;
+  }
+  b0 = file[*pos];
   if (b0 < 28) {
     x = 0;
   } else if (b0 == 28) {
-    x = ((*ptr)[1] << 8) + (*ptr)[2];
-    *ptr += 3;
+    if (*pos + 3 <= len) {
+      x = (file[*pos + 1] << 8) + file[*pos + 2];
+      *pos += 3;
+    }
   } else if (b0 == 29) {
-    x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
-    *ptr += 5;
+    if (*pos + 5 <= len) {
+      x = (file[*pos + 1] << 24) + (file[*pos + 2] << 16) +
+         (file[*pos + 3] << 8) + file[*pos + 4];
+      *pos += 5;
+    }
   } else if (b0 == 30) {
-    *ptr += 1;
+    *pos += 1;
     i = 0;
     do {
-      b = *(*ptr)++;
+      if (*pos >= len) {
+       break;
+      }
+      b = file[(*pos)++];
       nyb0 = b >> 4;
       nyb1 = b & 0x0f;
       if (nyb0 == 0xf) {
@@ -2141,32 +2459,35 @@ double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
     x = 0;
   } else if (b0 < 247) {
     x = b0 - 139;
-    *ptr += 1;
+    *pos += 1;
   } else if (b0 < 251) {
-    x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
-    *ptr += 2;
+    if (*pos + 2 <= len) {
+      x = ((b0 - 247) << 8) + file[*pos + 1] + 108;
+      *pos += 2;
+    }
   } else {
-    x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
-    *ptr += 2;
+    if (*pos + 2 <= len) {
+      x = -((b0 - 251) << 8) - file[*pos + 1] - 108;
+      *pos += 2;
+    }
   }
   return x;
 }
 
 char *Type1CFontFile::getString(int sid, char *buf) {
-  Guchar *idxPtr0, *idxPtr1;
-  int n;
+  int idxPos, n;
 
   if (sid < 391) {
     strcpy(buf, type1CStdStrings[sid]);
   } else {
     sid -= 391;
-    idxPtr0 = getIndexValPtr(stringIdxPtr, sid);
-    idxPtr1 = getIndexValPtr(stringIdxPtr, sid + 1);
-    if ((n = idxPtr1 - idxPtr0) > 255) {
-      n = 255;
+    idxPos = getIndexValPos(stringIdxPos, sid, &n);
+    if (idxPos < 0 || n < 0 || n > 255 || idxPos + n > len) {
+      buf[0] = '\0';
+    } else {
+      strncpy(buf, (char *)&file[idxPos], n);
+      buf[n] = '\0';
     }
-    strncpy(buf, (char *)idxPtr0, n);
-    buf[n] = '\0';
   }
   return buf;
 }
@@ -2243,6 +2564,14 @@ struct T42Table {
   GBool required;              // required by the TrueType spec?
 };
 
+struct TTFontCmap {
+  int platform;
+  int encoding;
+  int offset;
+  int len;
+  int fmt;
+};
+
 // TrueType tables to be embedded in Type 42 fonts.
 // NB: the table names must be in alphabetical order here.
 #define nT42Tables 11
@@ -2526,20 +2855,22 @@ static char *macGlyphNames[258] = {
   "dmacron"
 };
 
-enum T42FontIndexMode {
-  t42FontModeUnicode,
-  t42FontModeCharCode,
-  t42FontModeCharCodeOffset,
-  t42FontModeMacRoman
+struct TrueTypeLoca {
+  int idx;
+  int pos;
+  int length;
 };
 
 TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
-  int pos, i;
+  int pos, pos2, i, idx, n, length;
+  Guint size, startPos, endPos;
 
   file = fileA;
   len = lenA;
 
   encoding = NULL;
+  cmaps = NULL;
+  nCmaps = 0;
 
   // read table directory
   nTables = getUShort(4);
@@ -2553,6 +2884,10 @@ TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
     tableHdrs[i].checksum = getULong(pos+4);
     tableHdrs[i].offset = getULong(pos+8);
     tableHdrs[i].length = getULong(pos+12);
+    if (tableHdrs[i].offset + tableHdrs[i].length < tableHdrs[i].offset ||
+       tableHdrs[i].offset + tableHdrs[i].length > (Guint)len) {
+      tableHdrs[i].offset = (Guint)-1;
+    }
     pos += 16;
   }
 
@@ -2568,6 +2903,31 @@ TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
     return;
   }
 
+  // some embedded TrueType fonts have an incorrect (too small) cmap
+  // table size
+  idx = seekTableIdx("cmap");
+  if (idx >= 0) {
+    pos = tableHdrs[idx].offset;
+    n = getUShort(pos + 2);
+    size = (Guint)(4 + 8 * n);
+    for (i = 0; i < n; ++i) {
+      startPos = getULong(pos + 4 + 8*i + 4);
+      length = getUShort(pos + startPos + 2);
+      endPos = startPos + length;
+      if (endPos > size) {
+       size = endPos;
+      }
+    }
+    if ((mungedCmapSize = size > tableHdrs[idx].length)) {
+#if 0 // don't bother printing this error message - it's too common
+      error(-1, "Bad cmap table size in TrueType font");
+#endif
+      tableHdrs[idx].length = size;
+    }
+  } else {
+    mungedCmapSize = gFalse;
+  }
+
   // read the 'head' table
   pos = seekTable("head");
   bbox[0] = getShort(pos + 36);
@@ -2579,6 +2939,23 @@ TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
   // read the 'maxp' table
   pos = seekTable("maxp");
   nGlyphs = getUShort(pos + 4);
+
+  // read the 'cmap' table
+  if ((pos = seekTable("cmap")) >= 0) {
+    pos2 = pos + 2;
+    if ((nCmaps = getUShort(pos2)) > 0) {
+      pos2 += 2;
+      cmaps = (TTFontCmap *)gmalloc(nCmaps * sizeof(TTFontCmap));
+      for (i = 0; i < nCmaps; ++i) {
+       cmaps[i].platform = getUShort(pos2);
+       cmaps[i].encoding = getUShort(pos2 + 2);
+       cmaps[i].offset = pos + getULong(pos2 + 4);
+       pos2 += 8;
+       cmaps[i].fmt = getUShort(cmaps[i].offset);
+       cmaps[i].len = getUShort(cmaps[i].offset + 2);
+      }
+    }
+  }
 }
 
 TrueTypeFontFile::~TrueTypeFontFile() {
@@ -2590,6 +2967,9 @@ TrueTypeFontFile::~TrueTypeFontFile() {
     }
     gfree(encoding);
   }
+  if (cmaps) {
+    gfree(cmaps);
+  }
   gfree(tableHdrs);
 }
 
@@ -2598,341 +2978,325 @@ char *TrueTypeFontFile::getName() {
 }
 
 char **TrueTypeFontFile::getEncoding() {
-  int cmap[256];
-  int nCmaps, cmapPlatform, cmapEncoding, cmapFmt;
-  int cmapLen, cmapOffset, cmapFirst;
-  int segCnt, segStart, segEnd, segDelta, segOffset;
-  int pos, i, j, k;
-  Guint fmt;
-  GString *s;
-  int stringIdx, stringPos, n;
+  int i;
 
-  if (encoding) {
-    return encoding;
+  if (!encoding) {
+    encoding = (char **)gmalloc(256 * sizeof(char *));
+    for (i = 0; i < 256; ++i) {
+      encoding[i] = NULL;
+    }
   }
+  return encoding;
+}
 
-  //----- construct the (char code) -> (glyph idx) mapping
+int TrueTypeFontFile::getNumCmaps() {
+  return nCmaps;
+}
 
-  // map everything to the missing glyph
-  for (i = 0; i < 256; ++i) {
-    cmap[i] = 0;
-  }
+int TrueTypeFontFile::getCmapPlatform(int i) {
+  return cmaps[i].platform;
+}
 
-  // look for the 'cmap' table
-  if ((pos = seekTable("cmap")) >= 0) {
-    nCmaps = getUShort(pos+2);
-
-    // if the font has a Windows-symbol cmap, use it;
-    // otherwise, use the first cmap in the table
-    for (i = 0; i < nCmaps; ++i) {
-      cmapPlatform = getUShort(pos + 4 + 8*i);
-      cmapEncoding = getUShort(pos + 4 + 8*i + 2);
-      if (cmapPlatform == 3 && cmapEncoding == 0) {
-       break;
-      }
-    }
-    if (i >= nCmaps) {
-      i = 0;
-      cmapPlatform = getUShort(pos + 4);
-      cmapEncoding = getUShort(pos + 4 + 2);
-    }
-    pos += getULong(pos + 4 + 8*i + 4);
+int TrueTypeFontFile::getCmapEncoding(int i) {
+  return cmaps[i].encoding;
+}
 
-    // read the cmap
-    cmapFmt = getUShort(pos);
-    switch (cmapFmt) {
-    case 0: // byte encoding table (Apple standard)
-      cmapLen = getUShort(pos + 2);
-      for (i = 0; i < cmapLen && i < 256; ++i) {
-       cmap[i] = getByte(pos + 6 + i);
-      }
-      break;
-    case 4: // segment mapping to delta values (Microsoft standard)
-      if (cmapPlatform == 3 && cmapEncoding == 0) {
-       // Windows-symbol uses char codes 0xf000 - 0xf0ff
-       cmapOffset = 0xf000;
-      } else {
-       cmapOffset = 0;
-      }
-      segCnt = getUShort(pos + 6) / 2;
-      for (i = 0; i < segCnt; ++i) {
-       segEnd = getUShort(pos + 14 + 2*i);
-       segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
-       segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
-       segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
-       if (segStart - cmapOffset <= 0xff &&
-           segEnd - cmapOffset >= 0) {
-         for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
-              j <= segEnd && j - cmapOffset <= 0xff;
-              ++j) {
-           if (segOffset == 0) {
-             k = (j + segDelta) & 0xffff;
-           } else {
-             k = getUShort(pos + 16 + 6*segCnt + 2*i +
-                           segOffset + 2 * (j - segStart));
-             if (k != 0) {
-               k = (k + segDelta) & 0xffff;
-             }
-           }
-           cmap[j - cmapOffset] = k;
-         }
-       }
-      }
-      break;
-    case 6: // trimmed table mapping
-      cmapFirst = getUShort(pos + 6);
-      cmapLen = getUShort(pos + 8);
-      for (i = cmapFirst; i < 256 && i < cmapFirst + cmapLen; ++i) {
-       cmap[i] = getUShort(pos + 10 + 2*i);
-      }
-      break;
-    default:
-      error(-1, "Unimplemented cmap format (%d) in TrueType font file",
-           cmapFmt);
-      break;
+int TrueTypeFontFile::findCmap(int platform, int enc) {
+  int i;
+
+  for (i = 0; i < nCmaps; ++i) {
+    if (cmaps[i].platform == platform && cmaps[i].encoding == enc) {
+      return i;
     }
   }
+  return -1;
+}
 
-  //----- construct the (glyph idx) -> (glyph name) mapping
-  //----- and compute the (char code) -> (glyph name) mapping
+Gushort TrueTypeFontFile::mapCodeToGID(int i, int c) {
+  if (i < 0 || i >= nCmaps) {
+    return 0;
+  }
+  return (Gushort)getCmapEntry(cmaps[i].fmt, cmaps[i].offset, c);
+}
 
-  encoding = (char **)gmalloc(256 * sizeof(char *));
-  for (i = 0; i < 256; ++i) {
-    encoding[i] = NULL;
+GHash *TrueTypeFontFile::getNameToGID() {
+  GHash *nameToGID;
+  Guint fmt;
+  GString *s;
+  int stringIdx, stringPos, pos, i, j, n;
+
+  if ((pos = seekTable("post")) < 0) {
+    return NULL;
   }
 
-  if ((pos = seekTable("post")) >= 0) {
-    fmt = getULong(pos);
+  fmt = getULong(pos);
+  nameToGID = NULL;
 
-    // Apple font
-    if (fmt == 0x00010000) {
-      for (i = 0; i < 256; ++i) {
-       j = (cmap[i] < 258) ? cmap[i] : 0;
-       encoding[i] = copyString(macGlyphNames[j]);
-      }
+  // Apple font
+  if (fmt == 0x00010000) {
+    nameToGID = new GHash(gTrue);
+    for (i = 0; i < 258; ++i) {
+      nameToGID->add(new GString(macGlyphNames[i]), (void *)i);
+    }
 
-    // Microsoft font
-    } else if (fmt == 0x00020000) {
-      stringIdx = 0;
-      stringPos = pos + 34 + 2*nGlyphs;
-      for (i = 0; i < 256; ++i) {
-       if (cmap[i] < nGlyphs) {
-         j = getUShort(pos + 34 + 2 * cmap[i]);
-         if (j < 258) {
-           encoding[i] = copyString(macGlyphNames[j]);
-         } else {
-           j -= 258;
-           if (j != stringIdx) {
-             for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
-                  stringIdx < j;
-                  ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
-           }
-           n = getByte(stringPos);
-           s = new GString(file + stringPos + 1, n);
-           encoding[i] = copyString(s->getCString());
-           delete s;
-           ++stringIdx;
-           stringPos += 1 + n;
-         }
-       } else {
-         encoding[i] = copyString(macGlyphNames[0]);
+  // Microsoft font
+  } else if (fmt == 0x00020000) {
+    nameToGID = new GHash(gTrue);
+    n = getUShort(pos + 32);
+    if (n > nGlyphs) {
+      n = nGlyphs;
+    }
+    stringIdx = 0;
+    stringPos = pos + 34 + 2*nGlyphs;
+    for (i = 0; i < nGlyphs; ++i) {
+      j = getUShort(pos + 34 + 2*i);
+      if (j < 258) {
+       nameToGID->remove(macGlyphNames[j]);
+       nameToGID->add(new GString(macGlyphNames[j]), (void *)i);
+      } else {
+       j -= 258;
+       if (j != stringIdx) {
+         for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs;
+              stringIdx < j;
+              ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
        }
-      }
-
-    // Apple subset
-    } else if (fmt == 0x000280000) {
-      for (i = 0; i < 256; ++i) {
-       if (cmap[i] < nGlyphs) {
-         j = i + getChar(pos + 32 + cmap[i]);
-       } else {
-         j = 0;
+       n = getByte(stringPos);
+       if (stringPos >= 0 && stringPos + 1 + n <= len) {
+         s = new GString(file + stringPos + 1, n);
+         nameToGID->remove(s);
+         nameToGID->add(s, (void *)i);
        }
-       encoding[i] = copyString(macGlyphNames[j]);
-      }
-
-    // Ugh, just assume the Apple glyph set
-    } else {
-      for (i = 0; i < 256; ++i) {
-       j = (cmap[i] < 258) ? cmap[i] : 0;
-       encoding[i] = copyString(macGlyphNames[j]);
+       ++stringIdx;
+       stringPos += 1 + n;
       }
     }
 
-  // no "post" table: assume the Apple glyph set
-  } else {
-    for (i = 0; i < 256; ++i) {
-      j = (cmap[i] < 258) ? cmap[i] : 0;
-      encoding[i] = copyString(macGlyphNames[j]);
+  // Apple subset
+  } else if (fmt == 0x000280000) {
+    nameToGID = new GHash(gTrue);
+    for (i = 0; i < nGlyphs; ++i) {
+      j = getByte(pos + 32 + i);
+      if (j < 258) {
+       nameToGID->remove(macGlyphNames[j]);
+       nameToGID->add(new GString(macGlyphNames[j]), (void *)i);
+      }
     }
   }
 
-  return encoding;
+  return nameToGID;
 }
 
 void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
-                                      CharCodeToUnicode *toUnicode,
-                                      GBool pdfFontHasEncoding, FILE *out) {
+                                      GBool pdfFontHasEncoding,
+                                      Gushort *codeToGID,
+                                      FontFileOutputFunc outputFunc,
+                                      void *outputStream) {
+  char buf[512];
+
   // write the header
-  fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+  sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+  (*outputFunc)(outputStream, buf, strlen(buf));
 
   // begin the font dictionary
-  fprintf(out, "10 dict begin\n");
-  fprintf(out, "/FontName /%s def\n", name);
-  fprintf(out, "/FontType 42 def\n");
-  fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
-  fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+  (*outputFunc)(outputStream, "10 dict begin\n", 14);
+  (*outputFunc)(outputStream, "/FontName /", 11);
+  (*outputFunc)(outputStream, name, strlen(name));
+  (*outputFunc)(outputStream, " def\n", 5);
+  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+  sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
          bbox[0], bbox[1], bbox[2], bbox[3]);
-  fprintf(out, "/PaintType 0 def\n");
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
 
   // write the guts of the dictionary
-  cvtEncoding(encodingA, out);
-  cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, out);
-  cvtSfnts(out, NULL);
+  cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream);
+  cvtCharStrings(encodingA, pdfFontHasEncoding, codeToGID,
+                outputFunc, outputStream);
+  cvtSfnts(outputFunc, outputStream, NULL);
 
   // end the dictionary and define the font
-  fprintf(out, "FontName currentdict end definefont pop\n");
+  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
 }
 
 void TrueTypeFontFile::convertToCIDType2(char *name, Gushort *cidMap,
-                                        int nCIDs, FILE *out) {
+                                        int nCIDs,
+                                        FontFileOutputFunc outputFunc,
+                                        void *outputStream) {
+  char buf[512];
   Gushort cid;
   int i, j, k;
 
   // write the header
-  fprintf(out, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+  sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0));
+  (*outputFunc)(outputStream, buf, strlen(buf));
 
   // begin the font dictionary
-  fprintf(out, "20 dict begin\n");
-  fprintf(out, "/CIDFontName /%s def\n", name);
-  fprintf(out, "/CIDFontType 2 def\n");
-  fprintf(out, "/FontType 42 def\n");
-  fprintf(out, "/CIDSystemInfo 3 dict dup begin\n");
-  fprintf(out, "  /Registry (Adobe) def\n");
-  fprintf(out, "  /Ordering (Identity) def\n");
-  fprintf(out, "  /Supplement 0 def\n");
-  fprintf(out, "  end def\n");
-  fprintf(out, "/GDBytes 2 def\n");
+  (*outputFunc)(outputStream, "20 dict begin\n", 14);
+  (*outputFunc)(outputStream, "/CIDFontName /", 14);
+  (*outputFunc)(outputStream, name, strlen(name));
+  (*outputFunc)(outputStream, " def\n", 5);
+  (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
+  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+  (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
+  (*outputFunc)(outputStream, "  /Registry (Adobe) def\n", 24);
+  (*outputFunc)(outputStream, "  /Ordering (Identity) def\n", 27);
+  (*outputFunc)(outputStream, "  /Supplement 0 def\n", 20);
+  (*outputFunc)(outputStream, "  end def\n", 10);
+  (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
   if (cidMap) {
-    fprintf(out, "/CIDCount %d def\n", nCIDs);
+    sprintf(buf, "/CIDCount %d def\n", nCIDs);
+    (*outputFunc)(outputStream, buf, strlen(buf));
     if (nCIDs > 32767) {
-      fprintf(out, "/CIDMap [");
+      (*outputFunc)(outputStream, "/CIDMap [", 9);
       for (i = 0; i < nCIDs; i += 32768 - 16) {
-       fprintf(out, "<\n");
+       (*outputFunc)(outputStream, "<\n", 2);
        for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
-         fprintf(out, "  ");
+         (*outputFunc)(outputStream, "  ", 2);
          for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
            cid = cidMap[i+j+k];
-           fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+           sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+           (*outputFunc)(outputStream, buf, strlen(buf));
          }
-         fprintf(out, "\n");
+         (*outputFunc)(outputStream, "\n", 1);
        }
-       fprintf(out, "  >");
+       (*outputFunc)(outputStream, "  >", 3);
       }
-      fprintf(out, "\n");
-      fprintf(out, "] def\n");
+      (*outputFunc)(outputStream, "\n", 1);
+      (*outputFunc)(outputStream, "] def\n", 6);
     } else {
-      fprintf(out, "/CIDMap <\n");
+      (*outputFunc)(outputStream, "/CIDMap <\n", 10);
       for (i = 0; i < nCIDs; i += 16) {
-       fprintf(out, "  ");
+       (*outputFunc)(outputStream, "  ", 2);
        for (j = 0; j < 16 && i+j < nCIDs; ++j) {
          cid = cidMap[i+j];
-         fprintf(out, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+         sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
+         (*outputFunc)(outputStream, buf, strlen(buf));
        }
-       fprintf(out, "\n");
+       (*outputFunc)(outputStream, "\n", 1);
       }
-      fprintf(out, "> def\n");
+      (*outputFunc)(outputStream, "> def\n", 6);
     }
   } else {
     // direct mapping - just fill the string(s) with s[i]=i
-    fprintf(out, "/CIDCount %d def\n", nGlyphs);
+    sprintf(buf, "/CIDCount %d def\n", nGlyphs);
+    (*outputFunc)(outputStream, buf, strlen(buf));
     if (nGlyphs > 32767) {
-      fprintf(out, "/CIDMap [\n");
+      (*outputFunc)(outputStream, "/CIDMap [\n", 10);
       for (i = 0; i < nGlyphs; i += 32767) {
        j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
-       fprintf(out, "  %d string 0 1 %d {\n", 2 * j, j - 1);
-       fprintf(out, "    2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
-       fprintf(out, "    1 index exch dup 2 mul 1 add exch %d add"
+       sprintf(buf, "  %d string 0 1 %d {\n", 2 * j, j - 1);
+       (*outputFunc)(outputStream, buf, strlen(buf));
+       sprintf(buf, "    2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
+       (*outputFunc)(outputStream, buf, strlen(buf));
+       sprintf(buf, "    1 index exch dup 2 mul 1 add exch %d add"
                " 255 and put\n", i);
-       fprintf(out, "  } for\n");
+       (*outputFunc)(outputStream, buf, strlen(buf));
+       (*outputFunc)(outputStream, "  } for\n", 8);
       }
-      fprintf(out, "] def\n");
+      (*outputFunc)(outputStream, "] def\n", 6);
     } else {
-      fprintf(out, "/CIDMap %d string\n", 2 * nGlyphs);
-      fprintf(out, "  0 1 %d {\n", nGlyphs - 1);
-      fprintf(out, "    2 copy dup 2 mul exch -8 bitshift put\n");
-      fprintf(out, "    1 index exch dup 2 mul 1 add exch 255 and put\n");
-      fprintf(out, "  } for\n");
-      fprintf(out, "def\n");
+      sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
+      (*outputFunc)(outputStream, buf, strlen(buf));
+      sprintf(buf, "  0 1 %d {\n", nGlyphs - 1);
+      (*outputFunc)(outputStream, buf, strlen(buf));
+      (*outputFunc)(outputStream,
+                   "    2 copy dup 2 mul exch -8 bitshift put\n", 42);
+      (*outputFunc)(outputStream,
+                   "    1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
+      (*outputFunc)(outputStream, "  } for\n", 8);
+      (*outputFunc)(outputStream, "def\n", 4);
     }
   }
-  fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
-  fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+  sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
          bbox[0], bbox[1], bbox[2], bbox[3]);
-  fprintf(out, "/PaintType 0 def\n");
-  fprintf(out, "/Encoding [] readonly def\n");
-  fprintf(out, "/CharStrings 1 dict dup begin\n");
-  fprintf(out, "  /.notdef 0 def\n");
-  fprintf(out, "  end readonly def\n");
+  (*outputFunc)(outputStream, buf, strlen(buf));
+  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
+  (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
+  (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
+  (*outputFunc)(outputStream, "  /.notdef 0 def\n", 17);
+  (*outputFunc)(outputStream, "  end readonly def\n", 19);
 
   // write the guts of the dictionary
-  cvtSfnts(out, NULL);
+  cvtSfnts(outputFunc, outputStream, NULL);
 
   // end the dictionary and define the font
-  fprintf(out, "CIDFontName currentdict end /CIDFont defineresource pop\n");
+  (*outputFunc)(outputStream,
+               "CIDFontName currentdict end /CIDFont defineresource pop\n",
+               56);
 }
 
 void TrueTypeFontFile::convertToType0(char *name, Gushort *cidMap,
-                                     int nCIDs, FILE *out) {
+                                     int nCIDs,
+                                     FontFileOutputFunc outputFunc,
+                                     void *outputStream) {
+  char buf[512];
   GString *sfntsName;
   int n, i, j;
 
   // write the Type 42 sfnts array
   sfntsName = (new GString(name))->append("_sfnts");
-  cvtSfnts(out, sfntsName);
+  cvtSfnts(outputFunc, outputStream, sfntsName);
   delete sfntsName;
 
   // write the descendant Type 42 fonts
   n = cidMap ? nCIDs : nGlyphs;
   for (i = 0; i < n; i += 256) {
-    fprintf(out, "10 dict begin\n");
-    fprintf(out, "/FontName /%s_%02x def\n", name, i >> 8);
-    fprintf(out, "/FontType 42 def\n");
-    fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
-    fprintf(out, "/FontBBox [%d %d %d %d] def\n",
+    (*outputFunc)(outputStream, "10 dict begin\n", 14);
+    (*outputFunc)(outputStream, "/FontName /", 11);
+    (*outputFunc)(outputStream, name, strlen(name));
+    sprintf(buf, "_%02x def\n", i >> 8);
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
+    (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+    sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
            bbox[0], bbox[1], bbox[2], bbox[3]);
-    fprintf(out, "/PaintType 0 def\n");
-    fprintf(out, "/sfnts %s_sfnts def\n", name);
-    fprintf(out, "/Encoding 256 array\n");
+    (*outputFunc)(outputStream, buf, strlen(buf));
+    (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
+    (*outputFunc)(outputStream, "/sfnts ", 7);
+    (*outputFunc)(outputStream, name, strlen(name));
+    (*outputFunc)(outputStream, "_sfnts def\n", 11);
+    (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
     for (j = 0; j < 256 && i+j < n; ++j) {
-      fprintf(out, "dup %d /c%02x put\n", j, j);
+      sprintf(buf, "dup %d /c%02x put\n", j, j);
+      (*outputFunc)(outputStream, buf, strlen(buf));
     }
-    fprintf(out, "readonly def\n");
-    fprintf(out, "/CharStrings 257 dict dup begin\n");
-    fprintf(out, "/.notdef 0 def\n");
+    (*outputFunc)(outputStream, "readonly def\n", 13);
+    (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
+    (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
     for (j = 0; j < 256 && i+j < n; ++j) {
-      fprintf(out, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
+      sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
+      (*outputFunc)(outputStream, buf, strlen(buf));
     }
-    fprintf(out, "end readonly def\n");
-    fprintf(out, "FontName currentdict end definefont pop\n");
+    (*outputFunc)(outputStream, "end readonly def\n", 17);
+    (*outputFunc)(outputStream,
+                 "FontName currentdict end definefont pop\n", 40);
   }
 
   // write the Type 0 parent font
-  fprintf(out, "16 dict begin\n");
-  fprintf(out, "/FontName /%s def\n", name);
-  fprintf(out, "/FontType 0 def\n");
-  fprintf(out, "/FontMatrix [1 0 0 1 0 0] def\n");
-  fprintf(out, "/FMapType 2 def\n");
-  fprintf(out, "/Encoding [\n");
+  (*outputFunc)(outputStream, "16 dict begin\n", 14);
+  (*outputFunc)(outputStream, "/FontName /", 11);
+  (*outputFunc)(outputStream, name, strlen(name));
+  (*outputFunc)(outputStream, " def\n", 5);
+  (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
+  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
+  (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
+  (*outputFunc)(outputStream, "/Encoding [\n", 12);
   for (i = 0; i < n; i += 256) {
-    fprintf(out, "%d\n", i >> 8);
+    sprintf(buf, "%d\n", i >> 8);
+    (*outputFunc)(outputStream, buf, strlen(buf));
   }
-  fprintf(out, "] def\n");
-  fprintf(out, "/FDepVector [\n");
+  (*outputFunc)(outputStream, "] def\n", 6);
+  (*outputFunc)(outputStream, "/FDepVector [\n", 14);
   for (i = 0; i < n; i += 256) {
-    fprintf(out, "/%s_%02x findfont\n", name, i >> 8);
+    (*outputFunc)(outputStream, "/", 1);
+    (*outputFunc)(outputStream, name, strlen(name));
+    sprintf(buf, "_%02x findfont\n", i >> 8);
+    (*outputFunc)(outputStream, buf, strlen(buf));
   }
-  fprintf(out, "] def\n");
-  fprintf(out, "FontName currentdict end definefont pop\n");
+  (*outputFunc)(outputStream, "] def\n", 6);
+  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
 }
 
 int TrueTypeFontFile::getByte(int pos) {
@@ -3004,7 +3368,7 @@ int TrueTypeFontFile::seekTable(char *tag) {
 
   for (i = 0; i < nTables; ++i) {
     if (!strncmp(tableHdrs[i].tag, tag, 4)) {
-      return tableHdrs[i].offset;
+      return (int)tableHdrs[i].offset;
     }
   }
   return -1;
@@ -3015,139 +3379,91 @@ int TrueTypeFontFile::seekTableIdx(char *tag) {
 
   for (i = 0; i < nTables; ++i) {
     if (!strncmp(tableHdrs[i].tag, tag, 4)) {
+      if (tableHdrs[i].offset == (Guint)-1) {
+       return -1;
+      }
       return i;
     }
   }
   return -1;
 }
 
-void TrueTypeFontFile::cvtEncoding(char **encodingA, FILE *out) {
+void TrueTypeFontFile::cvtEncoding(char **encodingA, GBool pdfFontHasEncoding,
+                                  FontFileOutputFunc outputFunc,
+                                  void *outputStream) {
   char *name;
+  char buf[64];
   int i;
 
-  fprintf(out, "/Encoding 256 array\n");
-  for (i = 0; i < 256; ++i) {
-    if (!(name = encodingA[i])) {
-      name = ".notdef";
+  (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
+  if (pdfFontHasEncoding) {
+    for (i = 0; i < 256; ++i) {
+      if (!(name = encodingA[i])) {
+       name = ".notdef";
+      }
+      sprintf(buf, "dup %d /", i);
+      (*outputFunc)(outputStream, buf, strlen(buf));
+      (*outputFunc)(outputStream, name, strlen(name));
+      (*outputFunc)(outputStream, " put\n", 5);
+    }
+  } else {
+    for (i = 0; i < 256; ++i) {
+      sprintf(buf, "dup %d /c%02x put\n", i, i);
+      (*outputFunc)(outputStream, buf, strlen(buf));
     }
-    fprintf(out, "dup %d /%s put\n", i, name);
   }
-  fprintf(out, "readonly def\n");
+  (*outputFunc)(outputStream, "readonly def\n", 13);
 }
 
 void TrueTypeFontFile::cvtCharStrings(char **encodingA,
-                                     CharCodeToUnicode *toUnicode,
-                                     GBool pdfFontHasEncoding, FILE *out) {
-  int unicodeCmap, macRomanCmap, msSymbolCmap;
-  int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapOffset;
-  T42FontIndexMode mode;
+                                     GBool pdfFontHasEncoding,
+                                     Gushort *codeToGID,
+                                     FontFileOutputFunc outputFunc,
+                                     void *outputStream) {
   char *name;
-  Unicode u;
-  int pos, i, j, k;
+  char buf[64], buf2[16];
+  int i, k;
 
   // always define '.notdef'
-  fprintf(out, "/CharStrings 256 dict dup begin\n");
-  fprintf(out, "/.notdef 0 def\n");
+  (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
+  (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
 
   // if there's no 'cmap' table, punt
-  if ((pos = seekTable("cmap")) < 0) {
-    goto err;
-  }
-
-  // To match up with the Adobe-defined behaviour, we choose a cmap
-  // like this:
-  // 1. If the PDF font has an encoding:
-  //    1a. If the TrueType font has a Microsoft Unicode cmap, use it,
-  //        and use the Unicode indexes, not the char codes.
-  //    1b. If the TrueType font has a Macintosh Roman cmap, use it,
-  //        and reverse map the char names through MacRomanEncoding to
-  //        get char codes.
-  // 2. If the PDF font does not have an encoding:
-  //    2a. If the TrueType font has a Macintosh Roman cmap, use it,
-  //        and use char codes directly.
-  //    2b. If the TrueType font has a Microsoft Symbol cmap, use it,
-  //        and use (0xf000 + char code).
-  // 3. If none of these rules apply, use the first cmap and hope for
-  //    the best (this shouldn't happen).
-  nCmaps = getUShort(pos+2);
-  unicodeCmap = macRomanCmap = msSymbolCmap = -1;
-  cmapOffset = 0;
-  for (i = 0; i < nCmaps; ++i) {
-    cmapPlatform = getUShort(pos + 4 + 8*i);
-    cmapEncoding = getUShort(pos + 4 + 8*i + 2);
-    if (cmapPlatform == 3 && cmapEncoding == 1) {
-      unicodeCmap = i;
-    } else if (cmapPlatform == 1 && cmapEncoding == 0) {
-      macRomanCmap = i;
-    } else if (cmapPlatform == 3 && cmapEncoding == 0) {
-      msSymbolCmap = i;
-    }
-  }
-  i = 0;
-  mode = t42FontModeCharCode;
-  if (pdfFontHasEncoding) {
-    if (unicodeCmap >= 0) {
-      i = unicodeCmap;
-      mode = t42FontModeUnicode;
-    } else if (macRomanCmap >= 0) {
-      i = macRomanCmap;
-      mode = t42FontModeMacRoman;
-    }
-  } else {
-    if (macRomanCmap >= 0) {
-      i = macRomanCmap;
-      mode = t42FontModeCharCode;
-    } else if (msSymbolCmap >= 0) {
-      i = msSymbolCmap;
-      mode = t42FontModeCharCodeOffset;
-      cmapOffset = 0xf000;
-    }
-  }
-  cmapPlatform = getUShort(pos + 4 + 8*i);
-  cmapEncoding = getUShort(pos + 4 + 8*i + 2);
-  pos += getULong(pos + 4 + 8*i + 4);
-  cmapFmt = getUShort(pos);
-  if (cmapFmt != 0 && cmapFmt != 4 && cmapFmt != 6) {
-    error(-1, "Unimplemented cmap format (%d) in TrueType font file",
-         cmapFmt);
+  if (nCmaps == 0) {
     goto err;
   }
 
   // map char name to glyph index:
   // 1. use encoding to map name to char code
-  // 2. use cmap to map char code to glyph index
-  j = 0; // make gcc happy
-  for (i = 0; i < 256; ++i) {
-    name = encodingA[i];
+  // 2. use codeToGID to map char code to glyph index
+  // N.B. We do this in reverse order because font subsets can have
+  //      weird encodings that use the same character name twice, and
+  //      the first definition is probably the one we want.
+  k = 0; // make gcc happy
+  for (i = 255; i >= 0; --i) {
+    if (pdfFontHasEncoding) {
+      name = encodingA[i];
+    } else {
+      sprintf(buf2, "c%02x", i);
+      name = buf2;
+    }
     if (name && strcmp(name, ".notdef")) {
-      switch (mode) {
-      case t42FontModeUnicode:
-       toUnicode->mapToUnicode((CharCode)i, &u, 1);
-       j = (int)u;
-       break;
-      case t42FontModeCharCode:
-       j = i;
-       break;
-      case t42FontModeCharCodeOffset:
-       j = cmapOffset + i;
-       break;
-      case t42FontModeMacRoman:
-       j = globalParams->getMacRomanCharCode(name);
-       break;
-      }
+      k = codeToGID[i];
       // note: Distiller (maybe Adobe's PS interpreter in general)
       // doesn't like TrueType fonts that have CharStrings entries
       // which point to nonexistent glyphs, hence the (k < nGlyphs)
       // test
-      if ((k = getCmapEntry(cmapFmt, pos, j)) > 0 &&
-         k < nGlyphs) {
-       fprintf(out, "/%s %d def\n", name, k);
+      if (k > 0 && k < nGlyphs) {
+       (*outputFunc)(outputStream, "/", 1);
+       (*outputFunc)(outputStream, name, strlen(name));
+       sprintf(buf, " %d def\n", k);
+       (*outputFunc)(outputStream, buf, strlen(buf));
       }
     }
   }
 
  err:
-  fprintf(out, "end readonly def\n");
+  (*outputFunc)(outputStream, "end readonly def\n", 17);
 }
 
 int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
@@ -3186,6 +3502,9 @@ int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
     segStart = getUShort(pos + 16 + 2*segCnt + 2*b);
     segDelta = getUShort(pos + 16 + 4*segCnt + 2*b);
     segOffset = getUShort(pos + 16 + 6*segCnt + 2*b);
+    if (code < segStart) {
+      return 0;
+    }
     if (segOffset == 0) {
       i = (code + segDelta) & 0xffff;
     } else {
@@ -3212,11 +3531,24 @@ int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
   return 0;
 }
 
-void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
+static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
+  return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx;
+}
+
+static int cmpTrueTypeLocaPos(const void *p1, const void *p2) {
+  if (((TrueTypeLoca *)p1)->pos == ((TrueTypeLoca *)p2)->pos) {
+    return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx;
+  } else {
+    return ((TrueTypeLoca *)p1)->pos - ((TrueTypeLoca *)p2)->pos;
+  }
+}
+
+void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
+                               void *outputStream, GString *name) {
   TTFontTableHdr newTableHdrs[nT42Tables];
   char tableDir[12 + nT42Tables*16];
   char headTable[54];
-  int *origLocaTable;
+  TrueTypeLoca *origLocaTable;
   char *locaTable;
   int nNewTables;
   Guint checksum;
@@ -3227,30 +3559,36 @@ void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
   memcpy(headTable, file + seekTable("head"), 54);
   headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0;
 
-  // read the original 'loca' table and construct the new one
-  // (pad each glyph out to a multiple of 4 bytes)
-  origLocaTable = (int *)gmalloc((nGlyphs + 1) * sizeof(int));
+  // read the original 'loca' table and sort it into proper order --
+  // some (non-compliant) fonts have out-of-order loca tables; in
+  // order to correctly handle the case where (compliant) fonts have
+  // empty entries in the middle of the table, cmpTrueTypeLocaPos uses
+  // pos as its primary sort key, and idx as its secondary key
+  // (ensuring that adjacent entries with the same pos value remain in
+  // the same order)
+  origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) *
+                                         sizeof(TrueTypeLoca));
   pos = seekTable("loca");
   for (i = 0; i <= nGlyphs; ++i) {
+    origLocaTable[i].idx = i;
     if (locaFmt) {
-      origLocaTable[i] = getULong(pos + 4*i);
+      origLocaTable[i].pos = getULong(pos + 4*i);
     } else {
-      origLocaTable[i] = 2 * getUShort(pos + 2*i);
+      origLocaTable[i].pos = 2 * getUShort(pos + 2*i);
     }
   }
-  locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
-  if (locaFmt) {
-    locaTable[0] = locaTable[1] = locaTable[2] = locaTable[3] = 0;
-  } else {
-    locaTable[0] = locaTable[1] = 0;
+  qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaPos);
+  for (i = 0; i < nGlyphs; ++i) {
+    origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos;
   }
+  origLocaTable[nGlyphs].length = 0;
+  qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx);
+
+  // construct the new 'loca' table, padding each glyph out to a
+  // multiple of 4 bytes
+  locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
   pos = 0;
-  for (i = 1; i <= nGlyphs; ++i) {
-    length = origLocaTable[i] - origLocaTable[i-1];
-    if (length & 3) {
-      length += 4 - (length & 3);
-    }
-    pos += length;
+  for (i = 0; i <= nGlyphs; ++i) {
     if (locaFmt) {
       locaTable[4*i  ] = (char)(pos >> 24);
       locaTable[4*i+1] = (char)(pos >> 16);
@@ -3260,6 +3598,11 @@ void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
       locaTable[2*i  ] = (char)(pos >> 9);
       locaTable[2*i+1] = (char)(pos >> 1);
     }
+    length = origLocaTable[i].length;
+    if (length & 3) {
+      length += 4 - (length & 3);
+    }
+    pos += length;
   }
 
   // count the number of tables
@@ -3289,11 +3632,15 @@ void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
       checksum = 0;
       glyfPos = seekTable("glyf");
       for (j = 0; j < nGlyphs; ++j) {
-       glyphLength = origLocaTable[j+1] - origLocaTable[j];
+       glyphLength = origLocaTable[j].length;
        pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0;
        length += glyphLength + pad;
-       checksum += computeTableChecksum(file + glyfPos + origLocaTable[j],
-                                        glyphLength);
+       if (glyphLength >= 0 &&
+           glyfPos + origLocaTable[j].pos + glyphLength <= len) {
+         checksum +=
+             computeTableChecksum(file + glyfPos + origLocaTable[j].pos,
+                                  glyphLength);
+       }
       }
     } else {
       if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) {
@@ -3364,27 +3711,31 @@ void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
 
   // start the sfnts array
   if (name) {
-    fprintf(out, "/%s [\n", name->getCString());
+    (*outputFunc)(outputStream, "/", 1);
+    (*outputFunc)(outputStream, name->getCString(), name->getLength());
+    (*outputFunc)(outputStream, " [\n", 3);
   } else {
-    fprintf(out, "/sfnts [\n");
+    (*outputFunc)(outputStream, "/sfnts [\n", 9);
   }
 
   // write the table directory
-  dumpString(tableDir, 12 + nNewTables*16, out);
+  dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
 
   // write the tables
   for (i = 0; i < nNewTables; ++i) {
     if (i == t42HeadTable) {
-      dumpString(headTable, 54, out);
+      dumpString(headTable, 54, outputFunc, outputStream);
     } else if (i == t42LocaTable) {
       length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
-      dumpString(locaTable, length, out);
+      dumpString(locaTable, length, outputFunc, outputStream);
     } else if (i == t42GlyfTable) {
       glyfPos = seekTable("glyf");
       for (j = 0; j < nGlyphs; ++j) {
-       length = origLocaTable[j+1] - origLocaTable[j];
-       if (length > 0) {
-         dumpString(file + glyfPos + origLocaTable[j], length, out);
+       length = origLocaTable[j].length;
+       if (length > 0 &&
+           glyfPos + origLocaTable[j].pos + length <= len) {
+         dumpString(file + glyfPos + origLocaTable[j].pos, length,
+                    outputFunc, outputStream);
        }
       }
     } else {
@@ -3392,40 +3743,48 @@ void TrueTypeFontFile::cvtSfnts(FILE *out, GString *name) {
       // already reported during the construction of the table
       // headers
       if ((length = newTableHdrs[i].length) > 0) {
-       dumpString(file + seekTable(t42Tables[i].tag), length, out);
+       j = seekTable(t42Tables[i].tag);
+       if (j >= 0) {
+         dumpString(file + seekTable(t42Tables[i].tag), length,
+                    outputFunc, outputStream);
+       }
       }
     }
   }
 
   // end the sfnts array
-  fprintf(out, "] def\n");
+  (*outputFunc)(outputStream, "] def\n", 6);
 
   gfree(origLocaTable);
   gfree(locaTable);
 }
 
-void TrueTypeFontFile::dumpString(char *s, int length, FILE *out) {
+void TrueTypeFontFile::dumpString(char *s, int length,
+                                 FontFileOutputFunc outputFunc,
+                                 void *outputStream) {
+  char buf[64];
   int pad, i, j;
 
-  fprintf(out, "<");
+  (*outputFunc)(outputStream, "<", 1);
   for (i = 0; i < length; i += 32) {
     for (j = 0; j < 32 && i+j < length; ++j) {
-      fprintf(out, "%02X", s[i+j] & 0xff);
+      sprintf(buf, "%02X", s[i+j] & 0xff);
+      (*outputFunc)(outputStream, buf, strlen(buf));
     }
     if (i % (65536 - 32) == 65536 - 64) {
-      fprintf(out, ">\n<");
+      (*outputFunc)(outputStream, ">\n<", 3);
     } else if (i+32 < length) {
-      fprintf(out, "\n");
+      (*outputFunc)(outputStream, "\n", 1);
     }
   }
   if (length & 3) {
     pad = 4 - (length & 3);
     for (i = 0; i < pad; ++i) {
-      fprintf(out, "00");
+      (*outputFunc)(outputStream, "00", 2);
     }
   }
   // add an extra zero byte because the Adobe Type 42 spec says so
-  fprintf(out, "00>\n");
+  (*outputFunc)(outputStream, "00>\n", 4);
 }
 
 Guint TrueTypeFontFile::computeTableChecksum(char *data, int length) {
@@ -3489,198 +3848,266 @@ void TrueTypeFontFile::writeTTF(FILE *out) {
   };
   GBool haveCmap, haveName, havePost;
   GBool dirCmap, dirName, dirPost;
-  int nNewTables, nAllTables, pad;
+  GBool unsortedLoca;
+  int nNewTables, nZeroLengthTables, nAllTables;
+  TTFontTableHdr *newTableHdrs;
   char *tableDir;
-  Guint t, pos;
-  int i, j;
+  TrueTypeLoca *origLocaTable;
+  char *locaTable;
+  int length, glyfLength;
+  Guint t, pos, pos2, pos3;
+  int i, j, k;
 
-  // check for missing tables
+  // check for missing/broken tables
   haveCmap = seekTable("cmap") >= 0;
   haveName = seekTable("name") >= 0;
   havePost = seekTable("post") >= 0;
+  unsortedLoca = gFalse;
+  pos = seekTable("loca");
+  pos2 = 0;
+  for (i = 0; i <= nGlyphs; ++i) {
+    if (locaFmt) {
+      pos3 = getULong(pos + 4*i);
+    } else {
+      pos3 = 2 * getUShort(pos + 2*i);
+    }
+    if (pos3 < pos2) {
+      unsortedLoca = gTrue;
+      break;
+    }
+    pos2 = pos3;
+  }
   nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1);
-  if (!nNewTables) {
-    // none are missing - write the TTF file as is
+  nZeroLengthTables = 0;
+  for (i = 0; i < nTables; ++i) {
+    if (tableHdrs[i].length == 0) {
+      ++nZeroLengthTables;
+    }
+  }
+  if (!nNewTables && !nZeroLengthTables && !mungedCmapSize && !unsortedLoca) {
+    // nothing is broken - write the TTF file as is
     fwrite(file, 1, len, out);
     return;
   }
 
+  // if the glyph data isn't sorted (as listed in the 'loca' table),
+  // construct a new 'loca' table
+  if (unsortedLoca) {
+    origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) *
+                                           sizeof(TrueTypeLoca));
+    pos = seekTable("loca");
+    for (i = 0; i <= nGlyphs; ++i) {
+      origLocaTable[i].idx = i;
+      if (locaFmt) {
+       origLocaTable[i].pos = getULong(pos + 4*i);
+      } else {
+       origLocaTable[i].pos = 2 * getUShort(pos + 2*i);
+      }
+    }
+    qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+         &cmpTrueTypeLocaPos);
+    for (i = 0; i < nGlyphs; ++i) {
+      origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos;
+    }
+    origLocaTable[nGlyphs].length = 0;
+    qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+         &cmpTrueTypeLocaIdx);
+    locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
+    pos = 0;
+    for (i = 0; i <= nGlyphs; ++i) {
+      if (locaFmt) {
+       locaTable[4*i  ] = (char)(pos >> 24);
+       locaTable[4*i+1] = (char)(pos >> 16);
+       locaTable[4*i+2] = (char)(pos >>  8);
+       locaTable[4*i+3] = (char) pos;
+      } else {
+       locaTable[2*i  ] = (char)(pos >> 9);
+       locaTable[2*i+1] = (char)(pos >> 1);
+      }
+      length = origLocaTable[i].length;
+      if (length & 3) {
+       length += 4 - (length & 3);
+      }
+      pos += length;
+    }
+    glyfLength = pos;
+  } else {
+    origLocaTable = NULL; // make gcc happy
+    locaTable = NULL; // make gcc happy
+    glyfLength = 0; // make gcc happy
+  }
+
   // construct the new table directory
-  nAllTables = nTables + nNewTables;
-  tableDir = (char *)gmalloc(12 + nAllTables * 16);
-  memcpy(tableDir, file, 12 + nTables * 16);
-  tableDir[4] = (char)((nAllTables >> 8) & 0xff);
-  tableDir[5] = (char)(nAllTables & 0xff);
-  for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ;
-  t = 1 << (4 + i);
-  tableDir[6] = (char)((t >> 8) & 0xff);
-  tableDir[7] = (char)(t & 0xff);
-  tableDir[8] = (char)((i >> 8) & 0xff);
-  tableDir[9] = (char)(i & 0xff);
-  t = nAllTables * 16 - t;
-  tableDir[10] = (char)((t >> 8) & 0xff);
-  tableDir[11] = (char)(t & 0xff);
+  nAllTables = nTables - nZeroLengthTables + nNewTables;
+  newTableHdrs = (TTFontTableHdr *)gmalloc(nAllTables *
+                                          sizeof(TTFontTableHdr));
   dirCmap = haveCmap;
   dirName = haveName;
   dirPost = havePost;
+  pos = 12 + nAllTables * 16;
   j = 0;
-  pad = (len & 3) ? 4 - (len & 3) : 0;
-  pos = len + pad + 16 * nNewTables;
   for (i = 0; i < nTables; ++i) {
     if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) {
-      tableDir[12 + 16*j     ] = 'c';
-      tableDir[12 + 16*j +  1] = 'm';
-      tableDir[12 + 16*j +  2] = 'a';
-      tableDir[12 + 16*j +  3] = 'p';
-      tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-      tableDir[12 + 16*j +  5] = (char)0;
-      tableDir[12 + 16*j +  6] = (char)0;
-      tableDir[12 + 16*j +  7] = (char)0;
-      tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-      tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-      tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-      tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-      tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
-      tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
-      tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >>  8) & 0xff);
-      tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab)        & 0xff);
-      pos += sizeof(cmapTab);
+      memcpy(newTableHdrs[j].tag, "cmap", 4);
+      newTableHdrs[j].checksum = 0; //~ should compute the checksum
+      newTableHdrs[j].offset = pos;
+      pos += newTableHdrs[j].length = sizeof(cmapTab);
+      if (pos & 3) {
+       pos += 4 - (pos & 3);
+      }
       ++j;
       dirCmap = gTrue;
     }
     if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) {
-      tableDir[12 + 16*j     ] = 'n';
-      tableDir[12 + 16*j +  1] = 'a';
-      tableDir[12 + 16*j +  2] = 'm';
-      tableDir[12 + 16*j +  3] = 'e';
-      tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-      tableDir[12 + 16*j +  5] = (char)0;
-      tableDir[12 + 16*j +  6] = (char)0;
-      tableDir[12 + 16*j +  7] = (char)0;
-      tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-      tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-      tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-      tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-      tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
-      tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
-      tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >>  8) & 0xff);
-      tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab)        & 0xff);
-      pos += sizeof(nameTab);
+      memcpy(newTableHdrs[j].tag, "name", 4);
+      newTableHdrs[j].checksum = 0; //~ should compute the checksum
+      newTableHdrs[j].offset = pos;
+      pos += newTableHdrs[j].length = sizeof(nameTab);
+      if (pos & 3) {
+       pos += 4 - (pos & 3);
+      }
       ++j;
       dirName = gTrue;
     }
-    if (!dirName && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
-      tableDir[12 + 16*j     ] = 'p';
-      tableDir[12 + 16*j +  1] = 'o';
-      tableDir[12 + 16*j +  2] = 's';
-      tableDir[12 + 16*j +  3] = 't';
-      tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-      tableDir[12 + 16*j +  5] = (char)0;
-      tableDir[12 + 16*j +  6] = (char)0;
-      tableDir[12 + 16*j +  7] = (char)0;
-      tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-      tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-      tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-      tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-      tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
-      tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
-      tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >>  8) & 0xff);
-      tableDir[12 + 16*j + 15] = (char)( sizeof(postTab)        & 0xff);
-      pos += sizeof(postTab);
+    if (!dirPost && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
+      memcpy(newTableHdrs[j].tag, "post", 4);
+      newTableHdrs[j].checksum = 0; //~ should compute the checksum
+      newTableHdrs[j].offset = pos;
+      pos += newTableHdrs[j].length = sizeof(postTab);
+      if (pos & 3) {
+       pos += 4 - (pos & 3);
+      }
       ++j;
       dirPost = gTrue;
     }
-    memcpy(&tableDir[12 + 16*j], file + 12 + 16*i, 16);
-    t = tableHdrs[i].offset + nNewTables * 16;
-    tableDir[12 + 16*j +  8] = (char)((t >> 24) & 0xff);
-    tableDir[12 + 16*j +  9] = (char)((t >> 16) & 0xff);
-    tableDir[12 + 16*j + 10] = (char)((t >>  8) & 0xff);
-    tableDir[12 + 16*j + 11] = (char)( t        & 0xff);
-    ++j;
+    // throw away zero-length tables - they confuse FreeType
+    if (tableHdrs[i].length > 0) {
+      memcpy(newTableHdrs[j].tag, tableHdrs[i].tag, 4);
+      newTableHdrs[j].checksum = tableHdrs[i].checksum;
+      newTableHdrs[j].offset = pos;
+      if (unsortedLoca && !strncmp(tableHdrs[i].tag, "loca", 4)) {
+       newTableHdrs[j].length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+      } else if (unsortedLoca && !strncmp(tableHdrs[i].tag, "glyf", 4)) {
+       newTableHdrs[j].length = glyfLength;
+      } else {
+       newTableHdrs[j].length = tableHdrs[i].length;
+      }
+      pos += newTableHdrs[j].length;
+      if (pos & 3) {
+       pos += 4 - (pos & 3);
+      }
+      ++j;
+    }
   }
   if (!dirCmap) {
-    tableDir[12 + 16*j     ] = 'c';
-    tableDir[12 + 16*j +  1] = 'm';
-    tableDir[12 + 16*j +  2] = 'a';
-    tableDir[12 + 16*j +  3] = 'p';
-    tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-    tableDir[12 + 16*j +  5] = (char)0;
-    tableDir[12 + 16*j +  6] = (char)0;
-    tableDir[12 + 16*j +  7] = (char)0;
-    tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-    tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-    tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-    tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-    tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
-    tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
-    tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >>  8) & 0xff);
-    tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab)        & 0xff);
-    pos += sizeof(cmapTab);
+    memcpy(newTableHdrs[j].tag, "cmap", 4);
+    newTableHdrs[j].checksum = 0; //~ should compute the checksum
+    newTableHdrs[j].offset = pos;
+    pos += newTableHdrs[j].length = sizeof(cmapTab);
+    if (pos & 3) {
+      pos += 4 - (pos & 3);
+    }
     ++j;
-    dirCmap = gTrue;
   }
   if (!dirName) {
-    tableDir[12 + 16*j     ] = 'n';
-    tableDir[12 + 16*j +  1] = 'a';
-    tableDir[12 + 16*j +  2] = 'm';
-    tableDir[12 + 16*j +  3] = 'e';
-    tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-    tableDir[12 + 16*j +  5] = (char)0;
-    tableDir[12 + 16*j +  6] = (char)0;
-    tableDir[12 + 16*j +  7] = (char)0;
-    tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-    tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-    tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-    tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-    tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
-    tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
-    tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >>  8) & 0xff);
-    tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab)        & 0xff);
-    pos += sizeof(nameTab);
+    memcpy(newTableHdrs[j].tag, "name", 4);
+    newTableHdrs[j].checksum = 0; //~ should compute the checksum
+    newTableHdrs[j].offset = pos;
+    pos += newTableHdrs[j].length = sizeof(nameTab);
+    if (pos & 3) {
+      pos += 4 - (pos & 3);
+    }
     ++j;
-    dirName = gTrue;
   }
   if (!dirPost) {
-    tableDir[12 + 16*j     ] = 'p';
-    tableDir[12 + 16*j +  1] = 'o';
-    tableDir[12 + 16*j +  2] = 's';
-    tableDir[12 + 16*j +  3] = 't';
-    tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-    tableDir[12 + 16*j +  5] = (char)0;
-    tableDir[12 + 16*j +  6] = (char)0;
-    tableDir[12 + 16*j +  7] = (char)0;
-    tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-    tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-    tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-    tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-    tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
-    tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
-    tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >>  8) & 0xff);
-    tableDir[12 + 16*j + 15] = (char)( sizeof(postTab)        & 0xff);
-    pos += sizeof(postTab);
+    memcpy(newTableHdrs[j].tag, "post", 4);
+    newTableHdrs[j].checksum = 0; //~ should compute the checksum
+    newTableHdrs[j].offset = pos;
+    pos += newTableHdrs[j].length = sizeof(postTab);
+    if (pos & 3) {
+      pos += 4 - (pos & 3);
+    }
     ++j;
-    dirPost = gTrue;
+  }
+  tableDir = (char *)gmalloc(12 + nAllTables * 16);
+  tableDir[0] = 0x00;                                  // sfnt version
+  tableDir[1] = 0x01;
+  tableDir[2] = 0x00;
+  tableDir[3] = 0x00;
+  tableDir[4] = (char)((nAllTables >> 8) & 0xff);      // numTables
+  tableDir[5] = (char)(nAllTables & 0xff);
+  for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ;
+  t = 1 << (4 + i);
+  tableDir[6] = (char)((t >> 8) & 0xff);               // searchRange
+  tableDir[7] = (char)(t & 0xff);
+  tableDir[8] = (char)((i >> 8) & 0xff);               // entrySelector
+  tableDir[9] = (char)(i & 0xff);
+  t = nAllTables * 16 - t;
+  tableDir[10] = (char)((t >> 8) & 0xff);              // rangeShift
+  tableDir[11] = (char)(t & 0xff);
+  pos = 12;
+  for (i = 0; i < nAllTables; ++i) {
+    tableDir[pos   ] = newTableHdrs[i].tag[0];
+    tableDir[pos+ 1] = newTableHdrs[i].tag[1];
+    tableDir[pos+ 2] = newTableHdrs[i].tag[2];
+    tableDir[pos+ 3] = newTableHdrs[i].tag[3];
+    tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24);
+    tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16);
+    tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >>  8);
+    tableDir[pos+ 7] = (char) newTableHdrs[i].checksum;
+    tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24);
+    tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16);
+    tableDir[pos+10] = (char)(newTableHdrs[i].offset >>  8);
+    tableDir[pos+11] = (char) newTableHdrs[i].offset;
+    tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24);
+    tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16);
+    tableDir[pos+14] = (char)(newTableHdrs[i].length >>  8);
+    tableDir[pos+15] = (char) newTableHdrs[i].length;
+    pos += 16;
   }
 
   // write the table directory
   fwrite(tableDir, 1, 12 + 16 * nAllTables, out);
 
-  // write the original tables
-  fwrite(file + 12 + 16*nTables, 1, len - (12 + 16*nTables), out);
-
-  // write the new tables
-  for (i = 0; i < pad; ++i) {
-    fputc((char)0, out);
-  }
-  if (!haveCmap) {
-    fwrite(cmapTab, 1, sizeof(cmapTab), out);
-  }
-  if (!haveName) {
-    fwrite(nameTab, 1, sizeof(nameTab), out);
-  }
-  if (!havePost) {
-    fwrite(postTab, 1, sizeof(postTab), out);
+  // write the tables
+  for (i = 0; i < nAllTables; ++i) {
+    if (!haveCmap && !strncmp(newTableHdrs[i].tag, "cmap", 4)) {
+      fwrite(cmapTab, 1, newTableHdrs[i].length, out);
+    } else if (!haveName && !strncmp(newTableHdrs[i].tag, "name", 4)) {
+      fwrite(nameTab, 1, newTableHdrs[i].length, out);
+    } else if (!havePost && !strncmp(newTableHdrs[i].tag, "post", 4)) {
+      fwrite(postTab, 1, newTableHdrs[i].length, out);
+    } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "loca", 4)) {
+      fwrite(locaTable, 1, newTableHdrs[i].length, out);
+    } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "glyf", 4)) {
+      pos = seekTable("glyf");
+      for (j = 0; j < nGlyphs; ++j) {
+       length = origLocaTable[j].length;
+       if (length > 0 &&
+           pos + origLocaTable[j].pos + length <= (Guint)len) {
+         fwrite(file + pos + origLocaTable[j].pos, 1, length, out);
+         if ((k = length & 3)) {
+           for (; k < 4; ++k) {
+             fputc((char)0, out);
+           }
+         }
+       }
+      }
+    } else {
+      fwrite(file + seekTable(newTableHdrs[i].tag),
+            1, newTableHdrs[i].length, out);
+    }
+    if ((j = (newTableHdrs[i].length & 3))) {
+      for (; j < 4; ++j) {
+       fputc((char)0, out);
+      }
+    }
   }
-
+    
   gfree(tableDir);
+  gfree(newTableHdrs);
+  if (unsortedLoca) {
+    gfree(origLocaTable);
+    gfree(locaTable);
+  }
 }