Back to index

tetex-bin  3.0
FoFiTrueType.cc
Go to the documentation of this file.
00001 //========================================================================
00002 //
00003 // FoFiTrueType.cc
00004 //
00005 // Copyright 1999-2003 Glyph & Cog, LLC
00006 //
00007 //========================================================================
00008 
00009 #include <aconf.h>
00010 
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014 
00015 #include <stdlib.h>
00016 #include "gtypes.h"
00017 #include "gmem.h"
00018 #include "GString.h"
00019 #include "GHash.h"
00020 #include "FoFiTrueType.h"
00021 
00022 //
00023 // Terminology
00024 // -----------
00025 //
00026 // character code = number used as an element of a text string
00027 //
00028 // character name = glyph name = name for a particular glyph within a
00029 //                  font
00030 //
00031 // glyph index = GID = position (within some internal table in the font)
00032 //               where the instructions to draw a particular glyph are
00033 //               stored
00034 //
00035 // Type 1 fonts
00036 // ------------
00037 //
00038 // Type 1 fonts contain:
00039 //
00040 // Encoding: array of glyph names, maps char codes to glyph names
00041 //
00042 //           Encoding[charCode] = charName
00043 //
00044 // CharStrings: dictionary of instructions, keyed by character names,
00045 //              maps character name to glyph data
00046 //
00047 //              CharStrings[charName] = glyphData
00048 //
00049 // TrueType fonts
00050 // --------------
00051 //
00052 // TrueType fonts contain:
00053 //
00054 // 'cmap' table: mapping from character code to glyph index; there may
00055 //               be multiple cmaps in a TrueType font
00056 //
00057 //               cmap[charCode] = gid
00058 //
00059 // 'post' table: mapping from glyph index to glyph name
00060 //
00061 //               post[gid] = glyphName
00062 //
00063 // Type 42 fonts
00064 // -------------
00065 //
00066 // Type 42 fonts contain:
00067 //
00068 // Encoding: array of glyph names, maps char codes to glyph names
00069 //
00070 //           Encoding[charCode] = charName
00071 //
00072 // CharStrings: dictionary of glyph indexes, keyed by character names,
00073 //              maps character name to glyph index
00074 //
00075 //              CharStrings[charName] = gid
00076 //
00077 
00078 //------------------------------------------------------------------------
00079 
00080 struct TrueTypeTable {
00081   Guint tag;
00082   Guint checksum;
00083   int offset;
00084   int origOffset;
00085   int len;
00086 };
00087 
00088 struct TrueTypeCmap {
00089   int platform;
00090   int encoding;
00091   int offset;
00092   int len;
00093   int fmt;
00094 };
00095 
00096 struct TrueTypeLoca {
00097   int idx;
00098   int origOffset;
00099   int newOffset;
00100   int len;
00101 };
00102 
00103 #define cmapTag 0x636d6170
00104 #define glyfTag 0x676c7966
00105 #define locaTag 0x6c6f6361
00106 #define nameTag 0x6e616d65
00107 #define postTag 0x706f7374
00108 
00109 static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
00110   TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
00111   TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
00112 
00113   if (loca1->origOffset == loca2->origOffset) {
00114     return loca1->idx - loca2->idx;
00115   }
00116   return loca1->origOffset - loca2->origOffset;
00117 }
00118 
00119 static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
00120   TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
00121   TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
00122 
00123   return loca1->idx - loca2->idx;
00124 }
00125 
00126 static int cmpTrueTypeTableTag(const void *p1, const void *p2) {
00127   TrueTypeTable *tab1 = (TrueTypeTable *)p1;
00128   TrueTypeTable *tab2 = (TrueTypeTable *)p2;
00129 
00130   return (int)tab1->tag - (int)tab2->tag;
00131 }
00132 
00133 //------------------------------------------------------------------------
00134 
00135 struct T42Table {
00136   char *tag;                // 4-byte tag
00137   GBool required;           // required by the TrueType spec?
00138 };
00139 
00140 // TrueType tables to be embedded in Type 42 fonts.
00141 // NB: the table names must be in alphabetical order here.
00142 #define nT42Tables 11
00143 static T42Table t42Tables[nT42Tables] = {
00144   { "cvt ", gTrue  },
00145   { "fpgm", gTrue  },
00146   { "glyf", gTrue  },
00147   { "head", gTrue  },
00148   { "hhea", gTrue  },
00149   { "hmtx", gTrue  },
00150   { "loca", gTrue  },
00151   { "maxp", gTrue  },
00152   { "prep", gTrue  },
00153   { "vhea", gFalse },
00154   { "vmtx", gFalse }
00155 };
00156 #define t42HeadTable 3
00157 #define t42LocaTable 6
00158 #define t42GlyfTable 2
00159 
00160 //------------------------------------------------------------------------
00161 
00162 // Glyph names in some arbitrary standard order that Apple uses for
00163 // their TrueType fonts.
00164 static char *macGlyphNames[258] = {
00165   ".notdef",        "null",           "CR",             "space",
00166   "exclam",         "quotedbl",       "numbersign",     "dollar",
00167   "percent",        "ampersand",      "quotesingle",    "parenleft",
00168   "parenright",     "asterisk",       "plus",           "comma",
00169   "hyphen",         "period",         "slash",          "zero",
00170   "one",            "two",            "three",          "four",
00171   "five",           "six",            "seven",          "eight",
00172   "nine",           "colon",          "semicolon",      "less",
00173   "equal",          "greater",        "question",       "at",
00174   "A",              "B",              "C",              "D",
00175   "E",              "F",              "G",              "H",
00176   "I",              "J",              "K",              "L",
00177   "M",              "N",              "O",              "P",
00178   "Q",              "R",              "S",              "T",
00179   "U",              "V",              "W",              "X",
00180   "Y",              "Z",              "bracketleft",    "backslash",
00181   "bracketright",   "asciicircum",    "underscore",     "grave",
00182   "a",              "b",              "c",              "d",
00183   "e",              "f",              "g",              "h",
00184   "i",              "j",              "k",              "l",
00185   "m",              "n",              "o",              "p",
00186   "q",              "r",              "s",              "t",
00187   "u",              "v",              "w",              "x",
00188   "y",              "z",              "braceleft",      "bar",
00189   "braceright",     "asciitilde",     "Adieresis",      "Aring",
00190   "Ccedilla",       "Eacute",         "Ntilde",         "Odieresis",
00191   "Udieresis",      "aacute",         "agrave",         "acircumflex",
00192   "adieresis",      "atilde",         "aring",          "ccedilla",
00193   "eacute",         "egrave",         "ecircumflex",    "edieresis",
00194   "iacute",         "igrave",         "icircumflex",    "idieresis",
00195   "ntilde",         "oacute",         "ograve",         "ocircumflex",
00196   "odieresis",      "otilde",         "uacute",         "ugrave",
00197   "ucircumflex",    "udieresis",      "dagger",         "degree",
00198   "cent",           "sterling",       "section",        "bullet",
00199   "paragraph",      "germandbls",     "registered",     "copyright",
00200   "trademark",      "acute",          "dieresis",       "notequal",
00201   "AE",             "Oslash",         "infinity",       "plusminus",
00202   "lessequal",      "greaterequal",   "yen",            "mu1",
00203   "partialdiff",    "summation",      "product",        "pi",
00204   "integral",       "ordfeminine",    "ordmasculine",   "Ohm",
00205   "ae",             "oslash",         "questiondown",   "exclamdown",
00206   "logicalnot",     "radical",        "florin",         "approxequal",
00207   "increment",      "guillemotleft",  "guillemotright", "ellipsis",
00208   "nbspace",        "Agrave",         "Atilde",         "Otilde",
00209   "OE",             "oe",             "endash",         "emdash",
00210   "quotedblleft",   "quotedblright",  "quoteleft",      "quoteright",
00211   "divide",         "lozenge",        "ydieresis",      "Ydieresis",
00212   "fraction",       "currency",       "guilsinglleft",  "guilsinglright",
00213   "fi",             "fl",             "daggerdbl",      "periodcentered",
00214   "quotesinglbase", "quotedblbase",   "perthousand",    "Acircumflex",
00215   "Ecircumflex",    "Aacute",         "Edieresis",      "Egrave",
00216   "Iacute",         "Icircumflex",    "Idieresis",      "Igrave",
00217   "Oacute",         "Ocircumflex",    "applelogo",      "Ograve",
00218   "Uacute",         "Ucircumflex",    "Ugrave",         "dotlessi",
00219   "circumflex",     "tilde",          "overscore",      "breve",
00220   "dotaccent",      "ring",           "cedilla",        "hungarumlaut",
00221   "ogonek",         "caron",          "Lslash",         "lslash",
00222   "Scaron",         "scaron",         "Zcaron",         "zcaron",
00223   "brokenbar",      "Eth",            "eth",            "Yacute",
00224   "yacute",         "Thorn",          "thorn",          "minus",
00225   "multiply",       "onesuperior",    "twosuperior",    "threesuperior",
00226   "onehalf",        "onequarter",     "threequarters",  "franc",
00227   "Gbreve",         "gbreve",         "Idot",           "Scedilla",
00228   "scedilla",       "Cacute",         "cacute",         "Ccaron",
00229   "ccaron",         "dmacron"
00230 };
00231 
00232 //------------------------------------------------------------------------
00233 // FoFiTrueType
00234 //------------------------------------------------------------------------
00235 
00236 FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) {
00237   FoFiTrueType *ff;
00238 
00239   ff = new FoFiTrueType(fileA, lenA, gFalse);
00240   if (!ff->parsedOk) {
00241     delete ff;
00242     return NULL;
00243   }
00244   return ff;
00245 }
00246 
00247 FoFiTrueType *FoFiTrueType::load(char *fileName) {
00248   FoFiTrueType *ff;
00249   char *fileA;
00250   int lenA;
00251 
00252   if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
00253     return NULL;
00254   }
00255   ff = new FoFiTrueType(fileA, lenA, gTrue);
00256   if (!ff->parsedOk) {
00257     delete ff;
00258     return NULL;
00259   }
00260   return ff;
00261 }
00262 
00263 FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA):
00264   FoFiBase(fileA, lenA, freeFileDataA)
00265 {
00266   tables = NULL;
00267   nTables = 0;
00268   cmaps = NULL;
00269   nCmaps = 0;
00270   nameToGID = NULL;
00271   parsedOk = gFalse;
00272 
00273   parse();
00274 }
00275 
00276 FoFiTrueType::~FoFiTrueType() {
00277   gfree(tables);
00278   gfree(cmaps);
00279   delete nameToGID;
00280 }
00281 
00282 int FoFiTrueType::getNumCmaps() {
00283   return nCmaps;
00284 }
00285 
00286 int FoFiTrueType::getCmapPlatform(int i) {
00287   return cmaps[i].platform;
00288 }
00289 
00290 int FoFiTrueType::getCmapEncoding(int i) {
00291   return cmaps[i].encoding;
00292 }
00293 
00294 int FoFiTrueType::findCmap(int platform, int encoding) {
00295   int i;
00296 
00297   for (i = 0; i < nCmaps; ++i) {
00298     if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
00299       return i;
00300     }
00301   }
00302   return -1;
00303 }
00304 
00305 Gushort FoFiTrueType::mapCodeToGID(int i, int c) {
00306   Gushort gid;
00307   int segCnt, segEnd, segStart, segDelta, segOffset;
00308   int cmapFirst, cmapLen;
00309   int pos, a, b, m;
00310   GBool ok;
00311 
00312   if (i < 0 || i >= nCmaps) {
00313     return 0;
00314   }
00315   ok = gTrue;
00316   pos = cmaps[i].offset;
00317   switch (cmaps[i].fmt) {
00318   case 0:
00319     if (c < 0 || c >= cmaps[i].len - 6) {
00320       return 0;
00321     }
00322     gid = getU8(cmaps[i].offset + 6 + c, &ok);
00323     break;
00324   case 4:
00325     segCnt = getU16BE(pos + 6, &ok) / 2;
00326     a = -1;
00327     b = segCnt - 1;
00328     segEnd = getU16BE(pos + 14 + 2*b, &ok);
00329     if (c > segEnd) {
00330       // malformed font -- the TrueType spec requires the last segEnd
00331       // to be 0xffff
00332       return 0;
00333     }
00334     // invariant: seg[a].end < code <= seg[b].end
00335     while (b - a > 1 && ok) {
00336       m = (a + b) / 2;
00337       segEnd = getU16BE(pos + 14 + 2*m, &ok);
00338       if (segEnd < c) {
00339        a = m;
00340       } else {
00341        b = m;
00342       }
00343     }
00344     segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
00345     segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
00346     segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
00347     if (c < segStart) {
00348       return 0;
00349     }
00350     if (segOffset == 0) {
00351       gid = (c + segDelta) & 0xffff;
00352     } else {
00353       gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
00354                      segOffset + 2 * (c - segStart), &ok);
00355       if (gid != 0) {
00356        gid = (gid + segDelta) & 0xffff;
00357       }
00358     }
00359     break;
00360   case 6:
00361     cmapFirst = getU16BE(pos + 6, &ok);
00362     cmapLen = getU16BE(pos + 8, &ok);
00363     if (c < cmapFirst || c >= cmapFirst + cmapLen) {
00364       return 0;
00365     }
00366     gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
00367     break;
00368   default:
00369     return 0;
00370   }
00371   if (!ok) {
00372     return 0;
00373   }
00374   return gid;
00375 }
00376 
00377 int FoFiTrueType::mapNameToGID(char *name) {
00378   if (!nameToGID) {
00379     return 0;
00380   }
00381   return nameToGID->lookupInt(name);
00382 }
00383 
00384 int FoFiTrueType::getEmbeddingRights() {
00385   int i, fsType;
00386   GBool ok;
00387 
00388   if ((i = seekTable("OS/2")) < 0) {
00389     return 4;
00390   }
00391   ok = gTrue;
00392   fsType = getU16BE(tables[i].offset + 8, &ok);
00393   if (!ok) {
00394     return 4;
00395   }
00396   if (fsType & 0x0008) {
00397     return 2;
00398   }
00399   if (fsType & 0x0004) {
00400     return 1;
00401   }
00402   if (fsType & 0x0002) {
00403     return 0;
00404   }
00405   return 3;
00406 }
00407 
00408 void FoFiTrueType::convertToType42(char *psName, char **encoding,
00409                                Gushort *codeToGID,
00410                                FoFiOutputFunc outputFunc,
00411                                void *outputStream) {
00412   char buf[512];
00413   GBool ok;
00414 
00415   // write the header
00416   ok = gTrue;
00417   sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
00418   (*outputFunc)(outputStream, buf, strlen(buf));
00419 
00420   // begin the font dictionary
00421   (*outputFunc)(outputStream, "10 dict begin\n", 14);
00422   (*outputFunc)(outputStream, "/FontName /", 11);
00423   (*outputFunc)(outputStream, psName, strlen(psName));
00424   (*outputFunc)(outputStream, " def\n", 5);
00425   (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
00426   (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
00427   sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
00428          bbox[0], bbox[1], bbox[2], bbox[3]);
00429   (*outputFunc)(outputStream, buf, strlen(buf));
00430   (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
00431 
00432   // write the guts of the dictionary
00433   cvtEncoding(encoding, outputFunc, outputStream);
00434   cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
00435   cvtSfnts(outputFunc, outputStream, NULL);
00436 
00437   // end the dictionary and define the font
00438   (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
00439 }
00440 
00441 void FoFiTrueType::convertToCIDType2(char *psName,
00442                                  Gushort *cidMap, int nCIDs,
00443                                  FoFiOutputFunc outputFunc,
00444                                  void *outputStream) {
00445   char buf[512];
00446   Gushort cid;
00447   GBool ok;
00448   int i, j, k;
00449 
00450   // write the header
00451   ok = gTrue;
00452   sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
00453   (*outputFunc)(outputStream, buf, strlen(buf));
00454 
00455   // begin the font dictionary
00456   (*outputFunc)(outputStream, "20 dict begin\n", 14);
00457   (*outputFunc)(outputStream, "/CIDFontName /", 14);
00458   (*outputFunc)(outputStream, psName, strlen(psName));
00459   (*outputFunc)(outputStream, " def\n", 5);
00460   (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
00461   (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
00462   (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
00463   (*outputFunc)(outputStream, "  /Registry (Adobe) def\n", 24);
00464   (*outputFunc)(outputStream, "  /Ordering (Identity) def\n", 27);
00465   (*outputFunc)(outputStream, "  /Supplement 0 def\n", 20);
00466   (*outputFunc)(outputStream, "  end def\n", 10);
00467   (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
00468   if (cidMap) {
00469     sprintf(buf, "/CIDCount %d def\n", nCIDs);
00470     (*outputFunc)(outputStream, buf, strlen(buf));
00471     if (nCIDs > 32767) {
00472       (*outputFunc)(outputStream, "/CIDMap [", 9);
00473       for (i = 0; i < nCIDs; i += 32768 - 16) {
00474        (*outputFunc)(outputStream, "<\n", 2);
00475        for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
00476          (*outputFunc)(outputStream, "  ", 2);
00477          for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
00478            cid = cidMap[i+j+k];
00479            sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
00480            (*outputFunc)(outputStream, buf, strlen(buf));
00481          }
00482          (*outputFunc)(outputStream, "\n", 1);
00483        }
00484        (*outputFunc)(outputStream, "  >", 3);
00485       }
00486       (*outputFunc)(outputStream, "\n", 1);
00487       (*outputFunc)(outputStream, "] def\n", 6);
00488     } else {
00489       (*outputFunc)(outputStream, "/CIDMap <\n", 10);
00490       for (i = 0; i < nCIDs; i += 16) {
00491        (*outputFunc)(outputStream, "  ", 2);
00492        for (j = 0; j < 16 && i+j < nCIDs; ++j) {
00493          cid = cidMap[i+j];
00494          sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
00495          (*outputFunc)(outputStream, buf, strlen(buf));
00496        }
00497        (*outputFunc)(outputStream, "\n", 1);
00498       }
00499       (*outputFunc)(outputStream, "> def\n", 6);
00500     }
00501   } else {
00502     // direct mapping - just fill the string(s) with s[i]=i
00503     sprintf(buf, "/CIDCount %d def\n", nGlyphs);
00504     (*outputFunc)(outputStream, buf, strlen(buf));
00505     if (nGlyphs > 32767) {
00506       (*outputFunc)(outputStream, "/CIDMap [\n", 10);
00507       for (i = 0; i < nGlyphs; i += 32767) {
00508        j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
00509        sprintf(buf, "  %d string 0 1 %d {\n", 2 * j, j - 1);
00510        (*outputFunc)(outputStream, buf, strlen(buf));
00511        sprintf(buf, "    2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
00512        (*outputFunc)(outputStream, buf, strlen(buf));
00513        sprintf(buf, "    1 index exch dup 2 mul 1 add exch %d add"
00514               " 255 and put\n", i);
00515        (*outputFunc)(outputStream, buf, strlen(buf));
00516        (*outputFunc)(outputStream, "  } for\n", 8);
00517       }
00518       (*outputFunc)(outputStream, "] def\n", 6);
00519     } else {
00520       sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
00521       (*outputFunc)(outputStream, buf, strlen(buf));
00522       sprintf(buf, "  0 1 %d {\n", nGlyphs - 1);
00523       (*outputFunc)(outputStream, buf, strlen(buf));
00524       (*outputFunc)(outputStream,
00525                   "    2 copy dup 2 mul exch -8 bitshift put\n", 42);
00526       (*outputFunc)(outputStream,
00527                   "    1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
00528       (*outputFunc)(outputStream, "  } for\n", 8);
00529       (*outputFunc)(outputStream, "def\n", 4);
00530     }
00531   }
00532   (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
00533   sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
00534          bbox[0], bbox[1], bbox[2], bbox[3]);
00535   (*outputFunc)(outputStream, buf, strlen(buf));
00536   (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
00537   (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
00538   (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
00539   (*outputFunc)(outputStream, "  /.notdef 0 def\n", 17);
00540   (*outputFunc)(outputStream, "  end readonly def\n", 19);
00541 
00542   // write the guts of the dictionary
00543   cvtSfnts(outputFunc, outputStream, NULL);
00544 
00545   // end the dictionary and define the font
00546   (*outputFunc)(outputStream,
00547               "CIDFontName currentdict end /CIDFont defineresource pop\n",
00548               56);
00549 }
00550 
00551 void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
00552                               FoFiOutputFunc outputFunc,
00553                               void *outputStream) {
00554   char buf[512];
00555   GString *sfntsName;
00556   int n, i, j;
00557 
00558   // write the Type 42 sfnts array
00559   sfntsName = (new GString(psName))->append("_sfnts");
00560   cvtSfnts(outputFunc, outputStream, sfntsName);
00561   delete sfntsName;
00562 
00563   // write the descendant Type 42 fonts
00564   n = cidMap ? nCIDs : nGlyphs;
00565   for (i = 0; i < n; i += 256) {
00566     (*outputFunc)(outputStream, "10 dict begin\n", 14);
00567     (*outputFunc)(outputStream, "/FontName /", 11);
00568     (*outputFunc)(outputStream, psName, strlen(psName));
00569     sprintf(buf, "_%02x def\n", i >> 8);
00570     (*outputFunc)(outputStream, buf, strlen(buf));
00571     (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
00572     (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
00573     sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
00574            bbox[0], bbox[1], bbox[2], bbox[3]);
00575     (*outputFunc)(outputStream, buf, strlen(buf));
00576     (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
00577     (*outputFunc)(outputStream, "/sfnts ", 7);
00578     (*outputFunc)(outputStream, psName, strlen(psName));
00579     (*outputFunc)(outputStream, "_sfnts def\n", 11);
00580     (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
00581     for (j = 0; j < 256 && i+j < n; ++j) {
00582       sprintf(buf, "dup %d /c%02x put\n", j, j);
00583       (*outputFunc)(outputStream, buf, strlen(buf));
00584     }
00585     (*outputFunc)(outputStream, "readonly def\n", 13);
00586     (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
00587     (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
00588     for (j = 0; j < 256 && i+j < n; ++j) {
00589       sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
00590       (*outputFunc)(outputStream, buf, strlen(buf));
00591     }
00592     (*outputFunc)(outputStream, "end readonly def\n", 17);
00593     (*outputFunc)(outputStream,
00594                 "FontName currentdict end definefont pop\n", 40);
00595   }
00596 
00597   // write the Type 0 parent font
00598   (*outputFunc)(outputStream, "16 dict begin\n", 14);
00599   (*outputFunc)(outputStream, "/FontName /", 11);
00600   (*outputFunc)(outputStream, psName, strlen(psName));
00601   (*outputFunc)(outputStream, " def\n", 5);
00602   (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
00603   (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
00604   (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
00605   (*outputFunc)(outputStream, "/Encoding [\n", 12);
00606   for (i = 0; i < n; i += 256) {
00607     sprintf(buf, "%d\n", i >> 8);
00608     (*outputFunc)(outputStream, buf, strlen(buf));
00609   }
00610   (*outputFunc)(outputStream, "] def\n", 6);
00611   (*outputFunc)(outputStream, "/FDepVector [\n", 14);
00612   for (i = 0; i < n; i += 256) {
00613     (*outputFunc)(outputStream, "/", 1);
00614     (*outputFunc)(outputStream, psName, strlen(psName));
00615     sprintf(buf, "_%02x findfont\n", i >> 8);
00616     (*outputFunc)(outputStream, buf, strlen(buf));
00617   }
00618   (*outputFunc)(outputStream, "] def\n", 6);
00619   (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
00620 }
00621 
00622 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
00623                          void *outputStream) {
00624   static char cmapTab[20] = {
00625     0, 0,                   // table version number
00626     0, 1,                   // number of encoding tables
00627     0, 1,                   // platform ID
00628     0, 0,                   // encoding ID
00629     0, 0, 0, 12,            // offset of subtable
00630     0, 0,                   // subtable format
00631     0, 1,                   // subtable length
00632     0, 1,                   // subtable version
00633     0,                      // map char 0 -> glyph 0
00634     0                       // pad to multiple of four bytes
00635   };
00636   static char nameTab[8] = {
00637     0, 0,                   // format
00638     0, 0,                   // number of name records
00639     0, 6,                   // offset to start of string storage
00640     0, 0                    // pad to multiple of four bytes
00641   };
00642   static char postTab[32] = {
00643     0, 1, 0, 0,                    // format
00644     0, 0, 0, 0,                    // italic angle
00645     0, 0,                   // underline position
00646     0, 0,                   // underline thickness
00647     0, 0, 0, 0,                    // fixed pitch
00648     0, 0, 0, 0,                    // min Type 42 memory
00649     0, 0, 0, 0,                    // max Type 42 memory
00650     0, 0, 0, 0,                    // min Type 1 memory
00651     0, 0, 0, 0                     // max Type 1 memory
00652   };
00653   GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen;
00654   int nZeroLengthTables;
00655   TrueTypeLoca *locaTable;
00656   TrueTypeTable *newTables;
00657   int nNewTables, cmapIdx, cmapLen, glyfLen;
00658   char *tableDir;
00659   char locaBuf[4];
00660   GBool ok;
00661   Guint t;
00662   int pos, i, j, k, n;
00663 
00664   // check for missing tables
00665   missingCmap = (cmapIdx = seekTable("cmap")) < 0;
00666   missingName = seekTable("name") < 0;
00667   missingPost = seekTable("post") < 0;
00668 
00669   // read the loca table, check to see if it's sorted
00670   locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca));
00671   unsortedLoca = gFalse;
00672   i = seekTable("loca");
00673   pos = tables[i].offset;
00674   ok = gTrue;
00675   for (i = 0; i <= nGlyphs; ++i) {
00676     if (locaFmt) {
00677       locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
00678     } else {
00679       locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
00680     }
00681     if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
00682       unsortedLoca = gTrue;
00683     }
00684     locaTable[i].idx = i;
00685   }
00686 
00687   // check for zero-length tables
00688   nZeroLengthTables = 0;
00689   for (i = 0; i < nTables; ++i) {
00690     if (tables[i].len == 0) {
00691       ++nZeroLengthTables;
00692     }
00693   }
00694 
00695   // check for an incorrect cmap table length
00696   badCmapLen = gFalse;
00697   cmapLen = 0; // make gcc happy
00698   if (!missingCmap) {
00699     cmapLen = cmaps[0].offset + cmaps[0].len;
00700     for (i = 1; i < nCmaps; ++i) {
00701       if (cmaps[i].offset + cmaps[i].len > cmapLen) {
00702        cmapLen = cmaps[i].offset + cmaps[i].len;
00703       }
00704     }
00705     cmapLen -= tables[cmapIdx].offset;
00706     if (cmapLen > tables[cmapIdx].len) {
00707       badCmapLen = gTrue;
00708     }
00709   }
00710 
00711   // if nothing is broken, just write the TTF file as is
00712   if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
00713       !badCmapLen && nZeroLengthTables == 0) {
00714     (*outputFunc)(outputStream, (char *)file, len);
00715     goto done1;
00716   }
00717 
00718   // sort the 'loca' table: some (non-compliant) fonts have
00719   // out-of-order loca tables; in order to correctly handle the case
00720   // where (compliant) fonts have empty entries in the middle of the
00721   // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
00722   // and idx as its secondary key (ensuring that adjacent entries with
00723   // the same pos value remain in the same order)
00724   glyfLen = 0; // make gcc happy
00725   if (unsortedLoca) {
00726     qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
00727          &cmpTrueTypeLocaOffset);
00728     for (i = 0; i < nGlyphs; ++i) {
00729       locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
00730     }
00731     locaTable[nGlyphs].len = 0;
00732     qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
00733          &cmpTrueTypeLocaIdx);
00734     pos = 0;
00735     for (i = 0; i <= nGlyphs; ++i) {
00736       locaTable[i].newOffset = pos;
00737       pos += locaTable[i].len;
00738       if (pos & 3) {
00739        pos += 4 - (pos & 3);
00740       }
00741     }
00742     glyfLen = pos;
00743   }
00744 
00745   // construct the new table directory:
00746   // - keep all original tables with non-zero length
00747   // - fix the cmap table's length, if necessary
00748   // - add missing tables
00749   // - sort the table by tag
00750   // - compute new table positions, including 4-byte alignment
00751   nNewTables = nTables - nZeroLengthTables +
00752                (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
00753                (missingPost ? 1 : 0);
00754   newTables = (TrueTypeTable *)gmalloc(nNewTables * sizeof(TrueTypeTable));
00755   j = 0;
00756   for (i = 0; i < nTables; ++i) {
00757     if (tables[i].len > 0) {
00758       newTables[j] = tables[i];
00759       newTables[j].origOffset = tables[i].offset;
00760       if (newTables[j].tag == cmapTag && badCmapLen) {
00761        newTables[j].len = cmapLen;
00762       } else if (newTables[j].tag == locaTag && unsortedLoca) {
00763        newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
00764       } else if (newTables[j].tag == glyfTag && unsortedLoca) {
00765        newTables[j].len = glyfLen;
00766       }
00767       ++j;
00768     }
00769   }
00770   if (missingCmap) {
00771     newTables[j].tag = cmapTag;
00772     newTables[j].checksum = 0; //~ should compute the checksum
00773     newTables[j].len = sizeof(cmapTab);
00774     ++j;
00775   }
00776   if (missingName) {
00777     newTables[j].tag = nameTag;
00778     newTables[j].checksum = 0; //~ should compute the checksum
00779     newTables[j].len = sizeof(nameTab);
00780     ++j;
00781   }
00782   if (missingPost) {
00783     newTables[j].tag = postTag;
00784     newTables[j].checksum = 0; //~ should compute the checksum
00785     newTables[j].len = sizeof(postTab);
00786     ++j;
00787   }
00788   qsort(newTables, nNewTables, sizeof(TrueTypeTable),
00789        &cmpTrueTypeTableTag);
00790   pos = 12 + nNewTables * 16;
00791   for (i = 0; i < nNewTables; ++i) {
00792     newTables[i].offset = pos;
00793     pos += newTables[i].len;
00794     if (pos & 3) {
00795       pos += 4 - (pos & 3);
00796     }
00797   }
00798 
00799   // write the table directory
00800   tableDir = (char *)gmalloc(12 + nNewTables * 16);
00801   tableDir[0] = 0x00;                                   // sfnt version
00802   tableDir[1] = 0x01;
00803   tableDir[2] = 0x00;
00804   tableDir[3] = 0x00;
00805   tableDir[4] = (char)((nNewTables >> 8) & 0xff);       // numTables
00806   tableDir[5] = (char)(nNewTables & 0xff);
00807   for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
00808   t = 1 << (4 + i);
00809   tableDir[6] = (char)((t >> 8) & 0xff);         // searchRange
00810   tableDir[7] = (char)(t & 0xff);
00811   tableDir[8] = (char)((i >> 8) & 0xff);         // entrySelector
00812   tableDir[9] = (char)(i & 0xff);
00813   t = nNewTables * 16 - t;
00814   tableDir[10] = (char)((t >> 8) & 0xff);        // rangeShift
00815   tableDir[11] = (char)(t & 0xff);
00816   pos = 12;
00817   for (i = 0; i < nNewTables; ++i) {
00818     tableDir[pos   ] = (char)(newTables[i].tag >> 24);
00819     tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
00820     tableDir[pos+ 2] = (char)(newTables[i].tag >>  8);
00821     tableDir[pos+ 3] = (char) newTables[i].tag;
00822     tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
00823     tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
00824     tableDir[pos+ 6] = (char)(newTables[i].checksum >>  8);
00825     tableDir[pos+ 7] = (char) newTables[i].checksum;
00826     tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
00827     tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
00828     tableDir[pos+10] = (char)(newTables[i].offset >>  8);
00829     tableDir[pos+11] = (char) newTables[i].offset;
00830     tableDir[pos+12] = (char)(newTables[i].len >> 24);
00831     tableDir[pos+13] = (char)(newTables[i].len >> 16);
00832     tableDir[pos+14] = (char)(newTables[i].len >>  8);
00833     tableDir[pos+15] = (char) newTables[i].len;
00834     pos += 16;
00835   }
00836   (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
00837 
00838   // write the tables
00839   for (i = 0; i < nNewTables; ++i) {
00840     if (newTables[i].tag == cmapTag && missingCmap) {
00841       (*outputFunc)(outputStream, cmapTab, newTables[i].len);
00842     } else if (newTables[i].tag == nameTag && missingName) {
00843       (*outputFunc)(outputStream, nameTab, newTables[i].len);
00844     } else if (newTables[i].tag == postTag && missingPost) {
00845       (*outputFunc)(outputStream, postTab, newTables[i].len);
00846     } else if (newTables[i].tag == locaTag && unsortedLoca) {
00847       for (j = 0; j <= nGlyphs; ++j) {
00848        if (locaFmt) {
00849          locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
00850          locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
00851          locaBuf[2] = (char)(locaTable[j].newOffset >>  8);
00852          locaBuf[3] = (char) locaTable[j].newOffset;
00853          (*outputFunc)(outputStream, locaBuf, 4);
00854        } else {
00855          locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
00856          locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
00857          (*outputFunc)(outputStream, locaBuf, 2);
00858        }
00859       }
00860     } else if (newTables[i].tag == glyfTag && unsortedLoca) {
00861       pos = tables[seekTable("glyf")].offset;
00862       for (j = 0; j < nGlyphs; ++j) {
00863        n = locaTable[j].len;
00864        if (n > 0) {
00865          k = locaTable[j].origOffset;
00866          if (checkRegion(pos + k, n)) {
00867            (*outputFunc)(outputStream, (char *)file + pos + k, n);
00868          } else {
00869            for (k = 0; k < n; ++k) {
00870              (*outputFunc)(outputStream, "\0", 1);
00871            }
00872          }
00873          if ((k = locaTable[j].len & 3)) {
00874            (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
00875          }
00876        }
00877       }
00878     } else {
00879       if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
00880        (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
00881                     newTables[i].len);
00882       } else {
00883        for (j = 0; j < newTables[i].len; ++j) {
00884          (*outputFunc)(outputStream, "\0", 1);
00885        }
00886       }
00887     }
00888     if (newTables[i].len & 3) {
00889       (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
00890     }
00891   }
00892 
00893   gfree(tableDir);
00894   gfree(newTables);
00895  done1:
00896   gfree(locaTable);
00897 }
00898 
00899 void FoFiTrueType::cvtEncoding(char **encoding,
00900                             FoFiOutputFunc outputFunc,
00901                             void *outputStream) {
00902   char *name;
00903   char buf[64];
00904   int i;
00905 
00906   (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
00907   if (encoding) {
00908     for (i = 0; i < 256; ++i) {
00909       if (!(name = encoding[i])) {
00910        name = ".notdef";
00911       }
00912       sprintf(buf, "dup %d /", i);
00913       (*outputFunc)(outputStream, buf, strlen(buf));
00914       (*outputFunc)(outputStream, name, strlen(name));
00915       (*outputFunc)(outputStream, " put\n", 5);
00916     }
00917   } else {
00918     for (i = 0; i < 256; ++i) {
00919       sprintf(buf, "dup %d /c%02x put\n", i, i);
00920       (*outputFunc)(outputStream, buf, strlen(buf));
00921     }
00922   }
00923   (*outputFunc)(outputStream, "readonly def\n", 13);
00924 }
00925 
00926 void FoFiTrueType::cvtCharStrings(char **encoding,
00927                               Gushort *codeToGID,
00928                               FoFiOutputFunc outputFunc,
00929                               void *outputStream) {
00930   char *name;
00931   char buf[64], buf2[16];
00932   int i, k;
00933 
00934   // always define '.notdef'
00935   (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
00936   (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
00937 
00938   // if there's no 'cmap' table, punt
00939   if (nCmaps == 0) {
00940     goto err;
00941   }
00942 
00943   // map char name to glyph index:
00944   // 1. use encoding to map name to char code
00945   // 2. use codeToGID to map char code to glyph index
00946   // N.B. We do this in reverse order because font subsets can have
00947   //      weird encodings that use the same character name twice, and
00948   //      the first definition is probably the one we want.
00949   k = 0; // make gcc happy
00950   for (i = 255; i >= 0; --i) {
00951     if (encoding) {
00952       name = encoding[i];
00953     } else {
00954       sprintf(buf2, "c%02x", i);
00955       name = buf2;
00956     }
00957     if (name && strcmp(name, ".notdef")) {
00958       k = codeToGID[i];
00959       // note: Distiller (maybe Adobe's PS interpreter in general)
00960       // doesn't like TrueType fonts that have CharStrings entries
00961       // which point to nonexistent glyphs, hence the (k < nGlyphs)
00962       // test
00963       if (k > 0 && k < nGlyphs) {
00964        (*outputFunc)(outputStream, "/", 1);
00965        (*outputFunc)(outputStream, name, strlen(name));
00966        sprintf(buf, " %d def\n", k);
00967        (*outputFunc)(outputStream, buf, strlen(buf));
00968       }
00969     }
00970   }
00971 
00972  err:
00973   (*outputFunc)(outputStream, "end readonly def\n", 17);
00974 }
00975 
00976 void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
00977                          void *outputStream, GString *name) {
00978   Guchar headData[54];
00979   TrueTypeLoca *locaTable;
00980   Guchar *locaData;
00981   TrueTypeTable newTables[nT42Tables];
00982   Guchar tableDir[12 + nT42Tables*16];
00983   GBool ok;
00984   Guint checksum;
00985   int nNewTables;
00986   int length, pos, glyfPos, i, j, k;
00987 
00988   // construct the 'head' table, zero out the font checksum
00989   i = seekTable("head");
00990   pos = tables[i].offset;
00991   if (!checkRegion(pos, 54)) {
00992     return;
00993   }
00994   memcpy(headData, file + pos, 54);
00995   headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
00996 
00997   // read the original 'loca' table, pad entries out to 4 bytes, and
00998   // sort it into proper order -- some (non-compliant) fonts have
00999   // out-of-order loca tables; in order to correctly handle the case
01000   // where (compliant) fonts have empty entries in the middle of the
01001   // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
01002   // and idx as its secondary key (ensuring that adjacent entries with
01003   // the same pos value remain in the same order)
01004   locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca));
01005   i = seekTable("loca");
01006   pos = tables[i].offset;
01007   ok = gTrue;
01008   for (i = 0; i <= nGlyphs; ++i) {
01009     locaTable[i].idx = i;
01010     if (locaFmt) {
01011       locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
01012     } else {
01013       locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
01014     }
01015   }
01016   qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
01017        &cmpTrueTypeLocaOffset);
01018   for (i = 0; i < nGlyphs; ++i) {
01019     locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
01020   }
01021   locaTable[nGlyphs].len = 0;
01022   qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
01023        &cmpTrueTypeLocaIdx);
01024   pos = 0;
01025   for (i = 0; i <= nGlyphs; ++i) {
01026     locaTable[i].newOffset = pos;
01027     pos += locaTable[i].len;
01028     if (pos & 3) {
01029       pos += 4 - (pos & 3);
01030     }
01031   }
01032 
01033   // construct the new 'loca' table
01034   locaData = (Guchar *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
01035   for (i = 0; i <= nGlyphs; ++i) {
01036     pos = locaTable[i].newOffset;
01037     if (locaFmt) {
01038       locaData[4*i  ] = (Guchar)(pos >> 24);
01039       locaData[4*i+1] = (Guchar)(pos >> 16);
01040       locaData[4*i+2] = (Guchar)(pos >>  8);
01041       locaData[4*i+3] = (Guchar) pos;
01042     } else {
01043       locaData[2*i  ] = (Guchar)(pos >> 9);
01044       locaData[2*i+1] = (Guchar)(pos >> 1);
01045     }
01046   }
01047 
01048   // count the number of tables
01049   nNewTables = 0;
01050   for (i = 0; i < nT42Tables; ++i) {
01051     if (t42Tables[i].required ||
01052        seekTable(t42Tables[i].tag) >= 0) {
01053       ++nNewTables;
01054     }
01055   }
01056 
01057   // construct the new table headers, including table checksums
01058   // (pad each table out to a multiple of 4 bytes)
01059   pos = 12 + nNewTables*16;
01060   k = 0;
01061   for (i = 0; i < nT42Tables; ++i) {
01062     length = -1;
01063     checksum = 0; // make gcc happy
01064     if (i == t42HeadTable) {
01065       length = 54;
01066       checksum = computeTableChecksum(headData, 54);
01067     } else if (i == t42LocaTable) {
01068       length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
01069       checksum = computeTableChecksum(locaData, length);
01070     } else if (i == t42GlyfTable) {
01071       length = 0;
01072       checksum = 0;
01073       glyfPos = tables[seekTable("glyf")].offset;
01074       for (j = 0; j < nGlyphs; ++j) {
01075        length += locaTable[j].len;
01076        if (length & 3) {
01077          length += 4 - (length & 3);
01078        }
01079        if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
01080          checksum +=
01081              computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
01082                                locaTable[j].len);
01083        }
01084       }
01085     } else {
01086       if ((j = seekTable(t42Tables[i].tag)) >= 0) {
01087        length = tables[j].len;
01088        if (checkRegion(tables[j].offset, length)) {
01089          checksum = computeTableChecksum(file + tables[j].offset, length);
01090        }
01091       } else if (t42Tables[i].required) {
01092        //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
01093        //~       t42Tables[i].tag);
01094        length = 0;
01095        checksum = 0;
01096       }
01097     }
01098     if (length >= 0) {
01099       newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
01100                         ((t42Tables[i].tag[1] & 0xff) << 16) |
01101                         ((t42Tables[i].tag[2] & 0xff) <<  8) |
01102                          (t42Tables[i].tag[3] & 0xff);
01103       newTables[k].checksum = checksum;
01104       newTables[k].offset = pos;
01105       newTables[k].len = length;
01106       pos += length;
01107       if (pos & 3) {
01108        pos += 4 - (length & 3);
01109       }
01110       ++k;
01111     }
01112   }
01113 
01114   // construct the table directory
01115   tableDir[0] = 0x00;              // sfnt version
01116   tableDir[1] = 0x01;
01117   tableDir[2] = 0x00;
01118   tableDir[3] = 0x00;
01119   tableDir[4] = 0;          // numTables
01120   tableDir[5] = nNewTables;
01121   tableDir[6] = 0;          // searchRange
01122   tableDir[7] = (Guchar)128;
01123   tableDir[8] = 0;          // entrySelector
01124   tableDir[9] = 3;
01125   tableDir[10] = 0;         // rangeShift
01126   tableDir[11] = (Guchar)(16 * nNewTables - 128);
01127   pos = 12;
01128   for (i = 0; i < nNewTables; ++i) {
01129     tableDir[pos   ] = (Guchar)(newTables[i].tag >> 24);
01130     tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
01131     tableDir[pos+ 2] = (Guchar)(newTables[i].tag >>  8);
01132     tableDir[pos+ 3] = (Guchar) newTables[i].tag;
01133     tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
01134     tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
01135     tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >>  8);
01136     tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
01137     tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
01138     tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
01139     tableDir[pos+10] = (Guchar)(newTables[i].offset >>  8);
01140     tableDir[pos+11] = (Guchar) newTables[i].offset;
01141     tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
01142     tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
01143     tableDir[pos+14] = (Guchar)(newTables[i].len >>  8);
01144     tableDir[pos+15] = (Guchar) newTables[i].len;
01145     pos += 16;
01146   }
01147 
01148   // compute the font checksum and store it in the head table
01149   checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
01150   for (i = 0; i < nNewTables; ++i) {
01151     checksum += newTables[i].checksum;
01152   }
01153   checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
01154   headData[ 8] = (Guchar)(checksum >> 24);
01155   headData[ 9] = (Guchar)(checksum >> 16);
01156   headData[10] = (Guchar)(checksum >>  8);
01157   headData[11] = (Guchar) checksum;
01158 
01159   // start the sfnts array
01160   if (name) {
01161     (*outputFunc)(outputStream, "/", 1);
01162     (*outputFunc)(outputStream, name->getCString(), name->getLength());
01163     (*outputFunc)(outputStream, " [\n", 3);
01164   } else {
01165     (*outputFunc)(outputStream, "/sfnts [\n", 9);
01166   }
01167 
01168   // write the table directory
01169   dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
01170 
01171   // write the tables
01172   for (i = 0; i < nNewTables; ++i) {
01173     if (i == t42HeadTable) {
01174       dumpString(headData, 54, outputFunc, outputStream);
01175     } else if (i == t42LocaTable) {
01176       length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
01177       dumpString(locaData, length, outputFunc, outputStream);
01178     } else if (i == t42GlyfTable) {
01179       glyfPos = tables[seekTable("glyf")].offset;
01180       for (j = 0; j < nGlyphs; ++j) {
01181        if (locaTable[j].len > 0 &&
01182            checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
01183          dumpString(file + glyfPos + locaTable[j].origOffset,
01184                    locaTable[j].len, outputFunc, outputStream);
01185        }
01186       }
01187     } else {
01188       // length == 0 means the table is missing and the error was
01189       // already reported during the construction of the table
01190       // headers
01191       if ((length = newTables[i].len) > 0) {
01192        if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
01193            checkRegion(tables[j].offset, tables[j].len)) {
01194          dumpString(file + tables[j].offset, tables[j].len,
01195                    outputFunc, outputStream);
01196        }
01197       }
01198     }
01199   }
01200 
01201   // end the sfnts array
01202   (*outputFunc)(outputStream, "] def\n", 6);
01203 
01204   gfree(locaData);
01205   gfree(locaTable);
01206 }
01207 
01208 void FoFiTrueType::dumpString(Guchar *s, int length,
01209                            FoFiOutputFunc outputFunc,
01210                            void *outputStream) {
01211   char buf[64];
01212   int pad, i, j;
01213 
01214   (*outputFunc)(outputStream, "<", 1);
01215   for (i = 0; i < length; i += 32) {
01216     for (j = 0; j < 32 && i+j < length; ++j) {
01217       sprintf(buf, "%02X", s[i+j] & 0xff);
01218       (*outputFunc)(outputStream, buf, strlen(buf));
01219     }
01220     if (i % (65536 - 32) == 65536 - 64) {
01221       (*outputFunc)(outputStream, ">\n<", 3);
01222     } else if (i+32 < length) {
01223       (*outputFunc)(outputStream, "\n", 1);
01224     }
01225   }
01226   if (length & 3) {
01227     pad = 4 - (length & 3);
01228     for (i = 0; i < pad; ++i) {
01229       (*outputFunc)(outputStream, "00", 2);
01230     }
01231   }
01232   // add an extra zero byte because the Adobe Type 42 spec says so
01233   (*outputFunc)(outputStream, "00>\n", 4);
01234 }
01235 
01236 Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
01237   Guint checksum, word;
01238   int i;
01239 
01240   checksum = 0;
01241   for (i = 0; i+3 < length; i += 4) {
01242     word = ((data[i  ] & 0xff) << 24) +
01243            ((data[i+1] & 0xff) << 16) +
01244            ((data[i+2] & 0xff) <<  8) +
01245             (data[i+3] & 0xff);
01246     checksum += word;
01247   }
01248   if (length & 3) {
01249     word = 0;
01250     i = length & ~3;
01251     switch (length & 3) {
01252     case 3:
01253       word |= (data[i+2] & 0xff) <<  8;
01254     case 2:
01255       word |= (data[i+1] & 0xff) << 16;
01256     case 1:
01257       word |= (data[i  ] & 0xff) << 24;
01258       break;
01259     }
01260     checksum += word;
01261   }
01262   return checksum;
01263 }
01264 
01265 void FoFiTrueType::parse() {
01266   int pos, i, j;
01267 
01268   parsedOk = gTrue;
01269 
01270   // read the table directory
01271   nTables = getU16BE(4, &parsedOk);
01272   if (!parsedOk) {
01273     return;
01274   }
01275   tables = (TrueTypeTable *)gmalloc(nTables * sizeof(TrueTypeTable));
01276   pos = 12;
01277   for (i = 0; i < nTables; ++i) {
01278     tables[i].tag = getU32BE(pos, &parsedOk);
01279     tables[i].checksum = getU32BE(pos + 4, &parsedOk);
01280     tables[i].offset = (int)getU32BE(pos + 8, &parsedOk);
01281     tables[i].len = (int)getU32BE(pos + 12, &parsedOk);
01282     if (tables[i].offset + tables[i].len < tables[i].offset ||
01283        tables[i].offset + tables[i].len > len) {
01284       parsedOk = gFalse;
01285     }
01286     pos += 16;
01287   }
01288   if (!parsedOk) {
01289     return;
01290   }
01291 
01292   // check for tables that are required by both the TrueType spec and
01293   // the Type 42 spec
01294   if (seekTable("head") < 0 ||
01295       seekTable("hhea") < 0 ||
01296       seekTable("loca") < 0 ||
01297       seekTable("maxp") < 0 ||
01298       seekTable("glyf") < 0 ||
01299       seekTable("hmtx") < 0) {
01300     parsedOk = gFalse;
01301     return;
01302   }
01303 
01304   // read the cmaps
01305   if ((i = seekTable("cmap")) >= 0) {
01306     pos = tables[i].offset + 2;
01307     nCmaps = getU16BE(pos, &parsedOk);
01308     pos += 2;
01309     if (!parsedOk) {
01310       return;
01311     }
01312     cmaps = (TrueTypeCmap *)gmalloc(nCmaps * sizeof(TrueTypeCmap));
01313     for (j = 0; j < nCmaps; ++j) {
01314       cmaps[j].platform = getU16BE(pos, &parsedOk);
01315       cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
01316       cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
01317       pos += 8;
01318       cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
01319       cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
01320     }
01321     if (!parsedOk) {
01322       return;
01323     }
01324   } else {
01325     nCmaps = 0;
01326   }
01327 
01328   // get the number of glyphs from the maxp table
01329   i = seekTable("maxp");
01330   nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
01331   if (!parsedOk) {
01332     return;
01333   }
01334 
01335   // get the bbox and loca table format from the head table
01336   i = seekTable("head");
01337   bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
01338   bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
01339   bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
01340   bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
01341   locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
01342   if (!parsedOk) {
01343     return;
01344   }
01345 
01346   // read the post table
01347   readPostTable();
01348   if (!parsedOk) {
01349     return;
01350   }
01351 }
01352 
01353 void FoFiTrueType::readPostTable() {
01354   GString *name;
01355   int tablePos, postFmt, stringIdx, stringPos;
01356   int i, j, n, m;
01357 
01358   if ((i = seekTable("post")) < 0) {
01359     return;
01360   }
01361   tablePos = tables[i].offset;
01362   postFmt = getU32BE(tablePos, &parsedOk);
01363   if (!parsedOk) {
01364     return;
01365   }
01366   if (postFmt == 0x00010000) {
01367     nameToGID = new GHash(gTrue);
01368     for (i = 0; i < 258; ++i) {
01369       nameToGID->add(new GString(macGlyphNames[i]), i);
01370     }
01371   } else if (postFmt == 0x00020000) {
01372     nameToGID = new GHash(gTrue);
01373     n = getU16BE(tablePos + 32, &parsedOk);
01374     if (!parsedOk) {
01375       return;
01376     }
01377     if (n > nGlyphs) {
01378       n = nGlyphs;
01379     }
01380     stringIdx = 0;
01381     stringPos = tablePos + 34 + 2*n;
01382     for (i = 0; i < n; ++i) {
01383       j = getU16BE(tablePos + 34 + 2*i, &parsedOk);
01384       if (j < 258) {
01385        nameToGID->removeInt(macGlyphNames[j]);
01386        nameToGID->add(new GString(macGlyphNames[j]), i);
01387       } else {
01388        j -= 258;
01389        if (j != stringIdx) {
01390          for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
01391               stringIdx < j;
01392               ++stringIdx, stringPos += 1 + getU8(stringPos, &parsedOk)) ;
01393          if (!parsedOk) {
01394            return;
01395          }
01396        }
01397        m = getU8(stringPos, &parsedOk);
01398        if (!parsedOk || !checkRegion(stringPos + 1, m)) {
01399          parsedOk = gFalse;
01400          return;
01401        }
01402        name = new GString((char *)&file[stringPos + 1], m);
01403        nameToGID->removeInt(name);
01404        nameToGID->add(name, i);
01405        ++stringIdx;
01406        stringPos += 1 + m;
01407       }
01408     }
01409   } else if (postFmt == 0x00028000) {
01410     nameToGID = new GHash(gTrue);
01411     for (i = 0; i < nGlyphs; ++i) {
01412       j = getU8(tablePos + 32 + i, &parsedOk);
01413       if (!parsedOk) {
01414        return;
01415       }
01416       if (j < 258) {
01417        nameToGID->removeInt(macGlyphNames[j]);
01418        nameToGID->add(new GString(macGlyphNames[j]), i);
01419       }
01420     }
01421   }
01422 }
01423 
01424 int FoFiTrueType::seekTable(char *tag) {
01425   Guint tagI;
01426   int i;
01427 
01428   tagI = ((tag[0] & 0xff) << 24) |
01429          ((tag[1] & 0xff) << 16) |
01430          ((tag[2] & 0xff) << 8) |
01431           (tag[3] & 0xff);
01432   for (i = 0; i < nTables; ++i) {
01433     if (tables[i].tag == tagI) {
01434       return i;
01435     }
01436   }
01437   return -1;
01438 }