source: trunk/poppler/mypoppler/fofi/FoFiTrueType.cc @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 54.6 KB
Line 
1//========================================================================
2//
3// FoFiTrueType.cc
4//
5// Copyright 1999-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <config.h>
10
11#ifdef USE_GCC_PRAGMAS
12#pragma implementation
13#endif
14
15#include <stdlib.h>
16#include <string.h>
17#include "goo/gtypes.h"
18#include "goo/gmem.h"
19#include "goo/GooString.h"
20#include "goo/GooHash.h"
21#include "FoFiTrueType.h"
22
23//
24// Terminology
25// -----------
26//
27// character code = number used as an element of a text string
28//
29// character name = glyph name = name for a particular glyph within a
30//                  font
31//
32// glyph index = GID = position (within some internal table in the font)
33//               where the instructions to draw a particular glyph are
34//               stored
35//
36// Type 1 fonts
37// ------------
38//
39// Type 1 fonts contain:
40//
41// Encoding: array of glyph names, maps char codes to glyph names
42//
43//           Encoding[charCode] = charName
44//
45// CharStrings: dictionary of instructions, keyed by character names,
46//              maps character name to glyph data
47//
48//              CharStrings[charName] = glyphData
49//
50// TrueType fonts
51// --------------
52//
53// TrueType fonts contain:
54//
55// 'cmap' table: mapping from character code to glyph index; there may
56//               be multiple cmaps in a TrueType font
57//
58//               cmap[charCode] = gid
59//
60// 'post' table: mapping from glyph index to glyph name
61//
62//               post[gid] = glyphName
63//
64// Type 42 fonts
65// -------------
66//
67// Type 42 fonts contain:
68//
69// Encoding: array of glyph names, maps char codes to glyph names
70//
71//           Encoding[charCode] = charName
72//
73// CharStrings: dictionary of glyph indexes, keyed by character names,
74//              maps character name to glyph index
75//
76//              CharStrings[charName] = gid
77//
78
79//------------------------------------------------------------------------
80
81#define ttcfTag 0x74746366
82
83//------------------------------------------------------------------------
84
85struct TrueTypeTable {
86  Guint tag;
87  Guint checksum;
88  int offset;
89  int origOffset;
90  int len;
91};
92
93struct TrueTypeCmap {
94  int platform;
95  int encoding;
96  int offset;
97  int len;
98  int fmt;
99};
100
101struct TrueTypeLoca {
102  int idx;
103  int origOffset;
104  int newOffset;
105  int len;
106};
107
108#define cmapTag 0x636d6170
109#define glyfTag 0x676c7966
110#define headTag 0x68656164
111#define locaTag 0x6c6f6361
112#define nameTag 0x6e616d65
113#define postTag 0x706f7374
114
115static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
116  TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
117  TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
118
119  if (loca1->origOffset == loca2->origOffset) {
120    return loca1->idx - loca2->idx;
121  }
122  return loca1->origOffset - loca2->origOffset;
123}
124
125static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
126  TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
127  TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
128
129  return loca1->idx - loca2->idx;
130}
131
132static int cmpTrueTypeTableTag(const void *p1, const void *p2) {
133  TrueTypeTable *tab1 = (TrueTypeTable *)p1;
134  TrueTypeTable *tab2 = (TrueTypeTable *)p2;
135
136  return (int)tab1->tag - (int)tab2->tag;
137}
138
139//------------------------------------------------------------------------
140
141struct T42Table {
142  char *tag;                    // 4-byte tag
143  GBool required;               // required by the TrueType spec?
144};
145
146// TrueType tables to be embedded in Type 42 fonts.
147// NB: the table names must be in alphabetical order here.
148#define nT42Tables 11
149static T42Table t42Tables[nT42Tables] = {
150  { "cvt ", gTrue  },
151  { "fpgm", gTrue  },
152  { "glyf", gTrue  },
153  { "head", gTrue  },
154  { "hhea", gTrue  },
155  { "hmtx", gTrue  },
156  { "loca", gTrue  },
157  { "maxp", gTrue  },
158  { "prep", gTrue  },
159  { "vhea", gFalse },
160  { "vmtx", gFalse }
161};
162#define t42HeadTable  3
163#define t42LocaTable  6
164#define t42GlyfTable  2
165#define t42VheaTable  9
166#define t42VmtxTable 10
167
168//------------------------------------------------------------------------
169
170// Glyph names in some arbitrary standard order that Apple uses for
171// their TrueType fonts.
172static char *macGlyphNames[258] = {
173  ".notdef",        "null",           "CR",             "space",
174  "exclam",         "quotedbl",       "numbersign",     "dollar",
175  "percent",        "ampersand",      "quotesingle",    "parenleft",
176  "parenright",     "asterisk",       "plus",           "comma",
177  "hyphen",         "period",         "slash",          "zero",
178  "one",            "two",            "three",          "four",
179  "five",           "six",            "seven",          "eight",
180  "nine",           "colon",          "semicolon",      "less",
181  "equal",          "greater",        "question",       "at",
182  "A",              "B",              "C",              "D",
183  "E",              "F",              "G",              "H",
184  "I",              "J",              "K",              "L",
185  "M",              "N",              "O",              "P",
186  "Q",              "R",              "S",              "T",
187  "U",              "V",              "W",              "X",
188  "Y",              "Z",              "bracketleft",    "backslash",
189  "bracketright",   "asciicircum",    "underscore",     "grave",
190  "a",              "b",              "c",              "d",
191  "e",              "f",              "g",              "h",
192  "i",              "j",              "k",              "l",
193  "m",              "n",              "o",              "p",
194  "q",              "r",              "s",              "t",
195  "u",              "v",              "w",              "x",
196  "y",              "z",              "braceleft",      "bar",
197  "braceright",     "asciitilde",     "Adieresis",      "Aring",
198  "Ccedilla",       "Eacute",         "Ntilde",         "Odieresis",
199  "Udieresis",      "aacute",         "agrave",         "acircumflex",
200  "adieresis",      "atilde",         "aring",          "ccedilla",
201  "eacute",         "egrave",         "ecircumflex",    "edieresis",
202  "iacute",         "igrave",         "icircumflex",    "idieresis",
203  "ntilde",         "oacute",         "ograve",         "ocircumflex",
204  "odieresis",      "otilde",         "uacute",         "ugrave",
205  "ucircumflex",    "udieresis",      "dagger",         "degree",
206  "cent",           "sterling",       "section",        "bullet",
207  "paragraph",      "germandbls",     "registered",     "copyright",
208  "trademark",      "acute",          "dieresis",       "notequal",
209  "AE",             "Oslash",         "infinity",       "plusminus",
210  "lessequal",      "greaterequal",   "yen",            "mu1",
211  "partialdiff",    "summation",      "product",        "pi",
212  "integral",       "ordfeminine",    "ordmasculine",   "Ohm",
213  "ae",             "oslash",         "questiondown",   "exclamdown",
214  "logicalnot",     "radical",        "florin",         "approxequal",
215  "increment",      "guillemotleft",  "guillemotright", "ellipsis",
216  "nbspace",        "Agrave",         "Atilde",         "Otilde",
217  "OE",             "oe",             "endash",         "emdash",
218  "quotedblleft",   "quotedblright",  "quoteleft",      "quoteright",
219  "divide",         "lozenge",        "ydieresis",      "Ydieresis",
220  "fraction",       "currency",       "guilsinglleft",  "guilsinglright",
221  "fi",             "fl",             "daggerdbl",      "periodcentered",
222  "quotesinglbase", "quotedblbase",   "perthousand",    "Acircumflex",
223  "Ecircumflex",    "Aacute",         "Edieresis",      "Egrave",
224  "Iacute",         "Icircumflex",    "Idieresis",      "Igrave",
225  "Oacute",         "Ocircumflex",    "applelogo",      "Ograve",
226  "Uacute",         "Ucircumflex",    "Ugrave",         "dotlessi",
227  "circumflex",     "tilde",          "overscore",      "breve",
228  "dotaccent",      "ring",           "cedilla",        "hungarumlaut",
229  "ogonek",         "caron",          "Lslash",         "lslash",
230  "Scaron",         "scaron",         "Zcaron",         "zcaron",
231  "brokenbar",      "Eth",            "eth",            "Yacute",
232  "yacute",         "Thorn",          "thorn",          "minus",
233  "multiply",       "onesuperior",    "twosuperior",    "threesuperior",
234  "onehalf",        "onequarter",     "threequarters",  "franc",
235  "Gbreve",         "gbreve",         "Idot",           "Scedilla",
236  "scedilla",       "Cacute",         "cacute",         "Ccaron",
237  "ccaron",         "dmacron"
238};
239
240//------------------------------------------------------------------------
241// FoFiTrueType
242//------------------------------------------------------------------------
243
244FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int faceIndexA) {
245  FoFiTrueType *ff;
246
247  ff = new FoFiTrueType(fileA, lenA, gFalse, faceIndexA);
248  if (!ff->parsedOk) {
249    delete ff;
250    return NULL;
251  }
252  return ff;
253}
254
255FoFiTrueType *FoFiTrueType::load(char *fileName, int faceIndexA) {
256  FoFiTrueType *ff;
257  char *fileA;
258  int lenA;
259
260  if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
261    return NULL;
262  }
263  ff = new FoFiTrueType(fileA, lenA, gTrue, faceIndexA);
264  if (!ff->parsedOk) {
265    delete ff;
266    return NULL;
267  }
268  return ff;
269}
270
271FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA):
272  FoFiBase(fileA, lenA, freeFileDataA)
273{
274  tables = NULL;
275  nTables = 0;
276  cmaps = NULL;
277  nCmaps = 0;
278  nameToGID = NULL;
279  parsedOk = gFalse;
280  faceIndex = faceIndexA;
281
282  parse();
283}
284
285FoFiTrueType::~FoFiTrueType() {
286  gfree(tables);
287  gfree(cmaps);
288  if (nameToGID) {
289    delete nameToGID;
290  }
291}
292
293int FoFiTrueType::getNumCmaps() {
294  return nCmaps;
295}
296
297int FoFiTrueType::getCmapPlatform(int i) {
298  return cmaps[i].platform;
299}
300
301int FoFiTrueType::getCmapEncoding(int i) {
302  return cmaps[i].encoding;
303}
304
305int FoFiTrueType::findCmap(int platform, int encoding) {
306  int i;
307
308  for (i = 0; i < nCmaps; ++i) {
309    if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
310      return i;
311    }
312  }
313  return -1;
314}
315
316Gushort FoFiTrueType::mapCodeToGID(int i, int c) {
317  Gushort gid;
318  int segCnt, segEnd, segStart, segDelta, segOffset;
319  int cmapFirst, cmapLen;
320  int pos, a, b, m;
321  GBool ok;
322
323  if (i < 0 || i >= nCmaps) {
324    return 0;
325  }
326  ok = gTrue;
327  pos = cmaps[i].offset;
328  switch (cmaps[i].fmt) {
329  case 0:
330    if (c < 0 || c >= cmaps[i].len - 6) {
331      return 0;
332    }
333    gid = getU8(cmaps[i].offset + 6 + c, &ok);
334    break;
335  case 4:
336    segCnt = getU16BE(pos + 6, &ok) / 2;
337    a = -1;
338    b = segCnt - 1;
339    segEnd = getU16BE(pos + 14 + 2*b, &ok);
340    if (c > segEnd) {
341      // malformed font -- the TrueType spec requires the last segEnd
342      // to be 0xffff
343      return 0;
344    }
345    // invariant: seg[a].end < code <= seg[b].end
346    while (b - a > 1 && ok) {
347      m = (a + b) / 2;
348      segEnd = getU16BE(pos + 14 + 2*m, &ok);
349      if (segEnd < c) {
350        a = m;
351      } else {
352        b = m;
353      }
354    }
355    segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
356    segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
357    segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
358    if (c < segStart) {
359      return 0;
360    }
361    if (segOffset == 0) {
362      gid = (c + segDelta) & 0xffff;
363    } else {
364      gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
365                       segOffset + 2 * (c - segStart), &ok);
366      if (gid != 0) {
367        gid = (gid + segDelta) & 0xffff;
368      }
369    }
370    break;
371  case 6:
372    cmapFirst = getU16BE(pos + 6, &ok);
373    cmapLen = getU16BE(pos + 8, &ok);
374    if (c < cmapFirst || c >= cmapFirst + cmapLen) {
375      return 0;
376    }
377    gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
378    break;
379  default:
380    return 0;
381  }
382  if (!ok) {
383    return 0;
384  }
385  return gid;
386}
387
388int FoFiTrueType::mapNameToGID(char *name) {
389  if (!nameToGID) {
390    return 0;
391  }
392  return nameToGID->lookupInt(name);
393}
394
395int FoFiTrueType::getEmbeddingRights() {
396  int i, fsType;
397  GBool ok;
398
399  if ((i = seekTable("OS/2")) < 0) {
400    return 4;
401  }
402  ok = gTrue;
403  fsType = getU16BE(tables[i].offset + 8, &ok);
404  if (!ok) {
405    return 4;
406  }
407  if (fsType & 0x0008) {
408    return 2;
409  }
410  if (fsType & 0x0004) {
411    return 1;
412  }
413  if (fsType & 0x0002) {
414    return 0;
415  }
416  return 3;
417}
418
419void FoFiTrueType::convertToType42(char *psName, char **encoding,
420                                   Gushort *codeToGID,
421                                   FoFiOutputFunc outputFunc,
422                                   void *outputStream) {
423  char buf[512];
424  GBool ok;
425
426  // write the header
427  ok = gTrue;
428  sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
429  (*outputFunc)(outputStream, buf, strlen(buf));
430
431  // begin the font dictionary
432  (*outputFunc)(outputStream, "10 dict begin\n", 14);
433  (*outputFunc)(outputStream, "/FontName /", 11);
434  (*outputFunc)(outputStream, psName, strlen(psName));
435  (*outputFunc)(outputStream, " def\n", 5);
436  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
437  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
438  sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
439          bbox[0], bbox[1], bbox[2], bbox[3]);
440  (*outputFunc)(outputStream, buf, strlen(buf));
441  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
442
443  // write the guts of the dictionary
444  cvtEncoding(encoding, outputFunc, outputStream);
445  cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
446  cvtSfnts(outputFunc, outputStream, NULL, gFalse);
447
448  // end the dictionary and define the font
449  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
450}
451
452void FoFiTrueType::convertToCIDType2(char *psName,
453                                     Gushort *cidMap, int nCIDs,
454                                     GBool needVerticalMetrics,
455                                     FoFiOutputFunc outputFunc,
456                                     void *outputStream) {
457  char buf[512];
458  Gushort cid;
459  GBool ok;
460  int i, j, k;
461
462  // write the header
463  ok = gTrue;
464  sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
465  (*outputFunc)(outputStream, buf, strlen(buf));
466
467  // begin the font dictionary
468  (*outputFunc)(outputStream, "20 dict begin\n", 14);
469  (*outputFunc)(outputStream, "/CIDFontName /", 14);
470  (*outputFunc)(outputStream, psName, strlen(psName));
471  (*outputFunc)(outputStream, " def\n", 5);
472  (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
473  (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
474  (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
475  (*outputFunc)(outputStream, "  /Registry (Adobe) def\n", 24);
476  (*outputFunc)(outputStream, "  /Ordering (Identity) def\n", 27);
477  (*outputFunc)(outputStream, "  /Supplement 0 def\n", 20);
478  (*outputFunc)(outputStream, "  end def\n", 10);
479  (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
480  if (cidMap) {
481    sprintf(buf, "/CIDCount %d def\n", nCIDs);
482    (*outputFunc)(outputStream, buf, strlen(buf));
483    if (nCIDs > 32767) {
484      (*outputFunc)(outputStream, "/CIDMap [", 9);
485      for (i = 0; i < nCIDs; i += 32768 - 16) {
486        (*outputFunc)(outputStream, "<\n", 2);
487        for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
488          (*outputFunc)(outputStream, "  ", 2);
489          for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
490            cid = cidMap[i+j+k];
491            sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
492            (*outputFunc)(outputStream, buf, strlen(buf));
493          }
494          (*outputFunc)(outputStream, "\n", 1);
495        }
496        (*outputFunc)(outputStream, "  >", 3);
497      }
498      (*outputFunc)(outputStream, "\n", 1);
499      (*outputFunc)(outputStream, "] def\n", 6);
500    } else {
501      (*outputFunc)(outputStream, "/CIDMap <\n", 10);
502      for (i = 0; i < nCIDs; i += 16) {
503        (*outputFunc)(outputStream, "  ", 2);
504        for (j = 0; j < 16 && i+j < nCIDs; ++j) {
505          cid = cidMap[i+j];
506          sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
507          (*outputFunc)(outputStream, buf, strlen(buf));
508        }
509        (*outputFunc)(outputStream, "\n", 1);
510      }
511      (*outputFunc)(outputStream, "> def\n", 6);
512    }
513  } else {
514    // direct mapping - just fill the string(s) with s[i]=i
515    sprintf(buf, "/CIDCount %d def\n", nGlyphs);
516    (*outputFunc)(outputStream, buf, strlen(buf));
517    if (nGlyphs > 32767) {
518      (*outputFunc)(outputStream, "/CIDMap [\n", 10);
519      for (i = 0; i < nGlyphs; i += 32767) {
520        j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
521        sprintf(buf, "  %d string 0 1 %d {\n", 2 * j, j - 1);
522        (*outputFunc)(outputStream, buf, strlen(buf));
523        sprintf(buf, "    2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
524        (*outputFunc)(outputStream, buf, strlen(buf));
525        sprintf(buf, "    1 index exch dup 2 mul 1 add exch %d add"
526                " 255 and put\n", i);
527        (*outputFunc)(outputStream, buf, strlen(buf));
528        (*outputFunc)(outputStream, "  } for\n", 8);
529      }
530      (*outputFunc)(outputStream, "] def\n", 6);
531    } else {
532      sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
533      (*outputFunc)(outputStream, buf, strlen(buf));
534      sprintf(buf, "  0 1 %d {\n", nGlyphs - 1);
535      (*outputFunc)(outputStream, buf, strlen(buf));
536      (*outputFunc)(outputStream,
537                    "    2 copy dup 2 mul exch -8 bitshift put\n", 42);
538      (*outputFunc)(outputStream,
539                    "    1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
540      (*outputFunc)(outputStream, "  } for\n", 8);
541      (*outputFunc)(outputStream, "def\n", 4);
542    }
543  }
544  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
545  sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
546          bbox[0], bbox[1], bbox[2], bbox[3]);
547  (*outputFunc)(outputStream, buf, strlen(buf));
548  (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
549  (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
550  (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
551  (*outputFunc)(outputStream, "  /.notdef 0 def\n", 17);
552  (*outputFunc)(outputStream, "  end readonly def\n", 19);
553
554  // write the guts of the dictionary
555  cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics);
556
557  // end the dictionary and define the font
558  (*outputFunc)(outputStream,
559                "CIDFontName currentdict end /CIDFont defineresource pop\n",
560                56);
561}
562
563void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
564                                  GBool needVerticalMetrics,
565                                  FoFiOutputFunc outputFunc,
566                                  void *outputStream) {
567  char buf[512];
568  GooString *sfntsName;
569  int n, i, j;
570
571  // write the Type 42 sfnts array
572  sfntsName = (new GooString(psName))->append("_sfnts");
573  cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
574  delete sfntsName;
575
576  // write the descendant Type 42 fonts
577  n = cidMap ? nCIDs : nGlyphs;
578  for (i = 0; i < n; i += 256) {
579    (*outputFunc)(outputStream, "10 dict begin\n", 14);
580    (*outputFunc)(outputStream, "/FontName /", 11);
581    (*outputFunc)(outputStream, psName, strlen(psName));
582    sprintf(buf, "_%02x def\n", i >> 8);
583    (*outputFunc)(outputStream, buf, strlen(buf));
584    (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
585    (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
586    sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
587            bbox[0], bbox[1], bbox[2], bbox[3]);
588    (*outputFunc)(outputStream, buf, strlen(buf));
589    (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
590    (*outputFunc)(outputStream, "/sfnts ", 7);
591    (*outputFunc)(outputStream, psName, strlen(psName));
592    (*outputFunc)(outputStream, "_sfnts def\n", 11);
593    (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
594    for (j = 0; j < 256 && i+j < n; ++j) {
595      sprintf(buf, "dup %d /c%02x put\n", j, j);
596      (*outputFunc)(outputStream, buf, strlen(buf));
597    }
598    (*outputFunc)(outputStream, "readonly def\n", 13);
599    (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
600    (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
601    for (j = 0; j < 256 && i+j < n; ++j) {
602      sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
603      (*outputFunc)(outputStream, buf, strlen(buf));
604    }
605    (*outputFunc)(outputStream, "end readonly def\n", 17);
606    (*outputFunc)(outputStream,
607                  "FontName currentdict end definefont pop\n", 40);
608  }
609
610  // write the Type 0 parent font
611  (*outputFunc)(outputStream, "16 dict begin\n", 14);
612  (*outputFunc)(outputStream, "/FontName /", 11);
613  (*outputFunc)(outputStream, psName, strlen(psName));
614  (*outputFunc)(outputStream, " def\n", 5);
615  (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
616  (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
617  (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
618  (*outputFunc)(outputStream, "/Encoding [\n", 12);
619  for (i = 0; i < n; i += 256) {
620    sprintf(buf, "%d\n", i >> 8);
621    (*outputFunc)(outputStream, buf, strlen(buf));
622  }
623  (*outputFunc)(outputStream, "] def\n", 6);
624  (*outputFunc)(outputStream, "/FDepVector [\n", 14);
625  for (i = 0; i < n; i += 256) {
626    (*outputFunc)(outputStream, "/", 1);
627    (*outputFunc)(outputStream, psName, strlen(psName));
628    sprintf(buf, "_%02x findfont\n", i >> 8);
629    (*outputFunc)(outputStream, buf, strlen(buf));
630  }
631  (*outputFunc)(outputStream, "] def\n", 6);
632  (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
633}
634
635void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
636                            void *outputStream, char *name,
637                            Gushort *codeToGID) {
638  // this substitute cmap table maps char codes 0000-ffff directly to
639  // glyphs 0000-ffff
640  static char cmapTab[36] = {
641    0, 0,                       // table version number
642    0, 1,                       // number of encoding tables
643    0, 1,                       // platform ID
644    0, 0,                       // encoding ID
645    0, 0, 0, 12,                // offset of subtable
646    0, 4,                       // subtable format
647    0, 24,                      // subtable length
648    0, 0,                       // subtable version
649    0, 2,                       // segment count * 2
650    0, 2,                       // 2 * 2 ^ floor(log2(segCount))
651    0, 0,                       // floor(log2(segCount))
652    0, 0,                       // 2*segCount - 2*2^floor(log2(segCount))
653    (char)0xff, (char)0xff,     // endCount[0]
654    0, 0,                       // reserved
655    0, 0,                       // startCount[0]
656    0, 0,                       // idDelta[0]
657    0, 0                        // pad to a mulitple of four bytes
658  };
659  static char nameTab[8] = {
660    0, 0,                       // format
661    0, 0,                       // number of name records
662    0, 6,                       // offset to start of string storage
663    0, 0                        // pad to multiple of four bytes
664  };
665  static char postTab[32] = {
666    0, 1, 0, 0,                 // format
667    0, 0, 0, 0,                 // italic angle
668    0, 0,                       // underline position
669    0, 0,                       // underline thickness
670    0, 0, 0, 0,                 // fixed pitch
671    0, 0, 0, 0,                 // min Type 42 memory
672    0, 0, 0, 0,                 // max Type 42 memory
673    0, 0, 0, 0,                 // min Type 1 memory
674    0, 0, 0, 0                  // max Type 1 memory
675  };
676  GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen;
677  int nZeroLengthTables;
678  TrueTypeLoca *locaTable;
679  TrueTypeTable *newTables;
680  char *newNameTab, *newCmapTab;
681  int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
682  Guint locaChecksum, glyfChecksum, fileChecksum;
683  char *tableDir;
684  char locaBuf[4], checksumBuf[4];
685  GBool ok;
686  Guint t;
687  int pos, i, j, k, n;
688
689  // check for missing tables
690  missingCmap = (cmapIdx = seekTable("cmap")) < 0;
691  missingName = seekTable("name") < 0;
692  missingPost = seekTable("post") < 0;
693
694  // read the loca table, check to see if it's sorted
695  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
696  unsortedLoca = gFalse;
697  i = seekTable("loca");
698  pos = tables[i].offset;
699  ok = gTrue;
700  for (i = 0; i <= nGlyphs; ++i) {
701    if (locaFmt) {
702      locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
703    } else {
704      locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
705    }
706    if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
707      unsortedLoca = gTrue;
708    }
709    locaTable[i].idx = i;
710  }
711
712  // check for zero-length tables
713  nZeroLengthTables = 0;
714  for (i = 0; i < nTables; ++i) {
715    if (tables[i].len == 0) {
716      ++nZeroLengthTables;
717    }
718  }
719
720  // check for an incorrect cmap table length
721  badCmapLen = gFalse;
722  cmapLen = 0; // make gcc happy
723  if (!missingCmap) {
724    cmapLen = cmaps[0].offset + cmaps[0].len;
725    for (i = 1; i < nCmaps; ++i) {
726      if (cmaps[i].offset + cmaps[i].len > cmapLen) {
727        cmapLen = cmaps[i].offset + cmaps[i].len;
728      }
729    }
730    cmapLen -= tables[cmapIdx].offset;
731    if (cmapLen > tables[cmapIdx].len) {
732      badCmapLen = gTrue;
733    }
734  }
735
736  // if nothing is broken, just write the TTF file as is
737  if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
738      !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) {
739    (*outputFunc)(outputStream, (char *)file, len);
740    goto done1;
741  }
742
743  // sort the 'loca' table: some (non-compliant) fonts have
744  // out-of-order loca tables; in order to correctly handle the case
745  // where (compliant) fonts have empty entries in the middle of the
746  // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
747  // and idx as its secondary key (ensuring that adjacent entries with
748  // the same pos value remain in the same order)
749  glyfLen = 0; // make gcc happy
750  if (unsortedLoca) {
751    qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
752          &cmpTrueTypeLocaOffset);
753    for (i = 0; i < nGlyphs; ++i) {
754      locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
755    }
756    locaTable[nGlyphs].len = 0;
757    qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
758          &cmpTrueTypeLocaIdx);
759    pos = 0;
760    for (i = 0; i <= nGlyphs; ++i) {
761      locaTable[i].newOffset = pos;
762      pos += locaTable[i].len;
763      if (pos & 3) {
764        pos += 4 - (pos & 3);
765      }
766    }
767    glyfLen = pos;
768  }
769
770  // compute checksums for the loca and glyf tables
771  locaChecksum = glyfChecksum = 0;
772  if (unsortedLoca) {
773    if (locaFmt) {
774      for (j = 0; j <= nGlyphs; ++j) {
775        locaChecksum += locaTable[j].newOffset;
776      }
777    } else {
778      for (j = 0; j <= nGlyphs; j += 2) {
779        locaChecksum += locaTable[j].newOffset << 16;
780        if (j + 1 <= nGlyphs) {
781          locaChecksum += locaTable[j+1].newOffset;
782        }
783      }
784    }
785    pos = tables[seekTable("glyf")].offset;
786    for (j = 0; j < nGlyphs; ++j) {
787      n = locaTable[j].len;
788      if (n > 0) {
789        k = locaTable[j].origOffset;
790        if (checkRegion(pos + k, n)) {
791          glyfChecksum += computeTableChecksum(file + pos + k, n);
792        }
793      }
794    }
795  }
796
797  // construct the new name table
798  if (name) {
799    n = strlen(name);
800    newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
801    newNameTab = (char *)gmalloc(newNameLen);
802    memset(newNameTab, 0, newNameLen);
803    newNameTab[0] = 0;          // format selector
804    newNameTab[1] = 0;
805    newNameTab[2] = 0;          // number of name records
806    newNameTab[3] = 4;
807    newNameTab[4] = 0;          // offset to start of string storage
808    newNameTab[5] = 6 + 4*12;
809    next = 0;
810    for (i = 0; i < 4; ++i) {
811      newNameTab[6 + i*12 + 0] = 0;     // platform ID = Microsoft
812      newNameTab[6 + i*12 + 1] = 3;
813      newNameTab[6 + i*12 + 2] = 0;     // encoding ID = Unicode
814      newNameTab[6 + i*12 + 3] = 1;
815      newNameTab[6 + i*12 + 4] = 0x04;  // language ID = American English
816      newNameTab[6 + i*12 + 5] = 0x09;
817      newNameTab[6 + i*12 + 6] = 0;     // name ID
818      newNameTab[6 + i*12 + 7] = i + 1;
819      newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
820      newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
821      newNameTab[6 + i*12 + 10] = next >> 8;                // string offset
822      newNameTab[6 + i*12 + 11] = next & 0xff;
823      if (i+1 == 2) {
824        memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
825        next += 14;
826      } else {
827        for (j = 0; j < n; ++j) {
828          newNameTab[6 + 4*12 + next + 2*j] = 0;
829          newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
830        }
831        next += 2*n;
832      }
833    }
834  } else {
835    newNameLen = 0;
836    newNameTab = NULL;
837  }
838
839  // construct the new cmap table
840  if (codeToGID) {
841    newCmapLen = 44 + 256 * 2;
842    newCmapTab = (char *)gmalloc(newCmapLen);
843    newCmapTab[0] = 0;          // table version number = 0
844    newCmapTab[1] = 0;
845    newCmapTab[2] = 0;          // number of encoding tables = 1
846    newCmapTab[3] = 1;
847    newCmapTab[4] = 0;          // platform ID = Microsoft
848    newCmapTab[5] = 3;
849    newCmapTab[6] = 0;          // encoding ID = Unicode
850    newCmapTab[7] = 1;
851    newCmapTab[8] = 0;          // offset of subtable
852    newCmapTab[9] = 0;
853    newCmapTab[10] = 0;
854    newCmapTab[11] = 12;
855    newCmapTab[12] = 0;         // subtable format = 4
856    newCmapTab[13] = 4;
857    newCmapTab[14] = 0x02;      // subtable length
858    newCmapTab[15] = 0x20;
859    newCmapTab[16] = 0;         // subtable version = 0
860    newCmapTab[17] = 0;
861    newCmapTab[18] = 0;         // segment count * 2
862    newCmapTab[19] = 4;
863    newCmapTab[20] = 0;         // 2 * 2 ^ floor(log2(segCount))
864    newCmapTab[21] = 4;
865    newCmapTab[22] = 0;         // floor(log2(segCount))
866    newCmapTab[23] = 1;
867    newCmapTab[24] = 0;         // 2*segCount - 2*2^floor(log2(segCount))
868    newCmapTab[25] = 0;
869    newCmapTab[26] = 0x00;      // endCount[0]
870    newCmapTab[27] = (char)0xff;
871    newCmapTab[28] = (char)0xff; // endCount[1]
872    newCmapTab[29] = (char)0xff;
873    newCmapTab[30] = 0;         // reserved
874    newCmapTab[31] = 0;
875    newCmapTab[32] = 0x00;      // startCount[0]
876    newCmapTab[33] = 0x00;
877    newCmapTab[34] = (char)0xff; // startCount[1]
878    newCmapTab[35] = (char)0xff;
879    newCmapTab[36] = 0;         // idDelta[0]
880    newCmapTab[37] = 0;
881    newCmapTab[38] = 0;         // idDelta[1]
882    newCmapTab[39] = 1;
883    newCmapTab[40] = 0;         // idRangeOffset[0]
884    newCmapTab[41] = 4;
885    newCmapTab[42] = 0;         // idRangeOffset[1]
886    newCmapTab[43] = 0;
887    for (i = 0; i < 256; ++i) {
888      newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
889      newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
890    }
891  } else {
892    newCmapLen = 0;
893    newCmapTab = NULL;
894  }
895
896  // construct the new table directory:
897  // - keep all original tables with non-zero length
898  // - fix the cmap table's length, if necessary
899  // - add missing tables
900  // - sort the table by tag
901  // - compute new table positions, including 4-byte alignment
902  // - (re)compute table checksums
903  nNewTables = nTables - nZeroLengthTables +
904               (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
905               (missingPost ? 1 : 0);
906  newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
907  j = 0;
908  for (i = 0; i < nTables; ++i) {
909    if (tables[i].len > 0) {
910      newTables[j] = tables[i];
911      newTables[j].origOffset = tables[i].offset;
912      if (checkRegion(tables[i].offset, newTables[i].len)) {
913        newTables[j].checksum =
914            computeTableChecksum(file + tables[i].offset, tables[i].len);
915        if (tables[i].tag == headTag) {
916          // don't include the file checksum
917          newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
918        }
919      }
920      if (newTables[j].tag == cmapTag && codeToGID) {
921        newTables[j].len = newCmapLen;
922        newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
923                                                     newCmapLen);
924      } else if (newTables[j].tag == cmapTag && badCmapLen) {
925        newTables[j].len = cmapLen;
926      } else if (newTables[j].tag == locaTag && unsortedLoca) {
927        newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
928        newTables[j].checksum = locaChecksum;
929      } else if (newTables[j].tag == glyfTag && unsortedLoca) {
930        newTables[j].len = glyfLen;
931        newTables[j].checksum = glyfChecksum;
932      } else if (newTables[j].tag == nameTag && name) {
933        newTables[j].len = newNameLen;
934        newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
935                                                     newNameLen);
936      }
937      ++j;
938    }
939  }
940  if (missingCmap) {
941    newTables[j].tag = cmapTag;
942    if (codeToGID) {
943      newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
944                                                   newCmapLen);
945      newTables[j].len = newCmapLen;
946    } else {
947      newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
948                                                   sizeof(cmapTab));
949      newTables[j].len = sizeof(cmapTab);
950    }
951    ++j;
952  }
953  if (missingName) {
954    newTables[j].tag = nameTag;
955    if (name) {
956      newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
957                                                   newNameLen);
958      newTables[j].len = newNameLen;
959    } else {
960      newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
961                                                   sizeof(nameTab));
962      newTables[j].len = sizeof(nameTab);
963    }
964    ++j;
965  }
966  if (missingPost) {
967    newTables[j].tag = postTag;
968    newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
969                                                 sizeof(postTab));
970    newTables[j].len = sizeof(postTab);
971    ++j;
972  }
973  qsort(newTables, nNewTables, sizeof(TrueTypeTable),
974        &cmpTrueTypeTableTag);
975  pos = 12 + nNewTables * 16;
976  for (i = 0; i < nNewTables; ++i) {
977    newTables[i].offset = pos;
978    pos += newTables[i].len;
979    if (pos & 3) {
980      pos += 4 - (pos & 3);
981    }
982  }
983
984  // write the table directory
985  tableDir = (char *)gmalloc(12 + nNewTables * 16);
986  tableDir[0] = 0x00;                                   // sfnt version
987  tableDir[1] = 0x01;
988  tableDir[2] = 0x00;
989  tableDir[3] = 0x00;
990  tableDir[4] = (char)((nNewTables >> 8) & 0xff);       // numTables
991  tableDir[5] = (char)(nNewTables & 0xff);
992  for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
993  t = 1 << (4 + i);
994  tableDir[6] = (char)((t >> 8) & 0xff);                // searchRange
995  tableDir[7] = (char)(t & 0xff);
996  tableDir[8] = (char)((i >> 8) & 0xff);                // entrySelector
997  tableDir[9] = (char)(i & 0xff);
998  t = nNewTables * 16 - t;
999  tableDir[10] = (char)((t >> 8) & 0xff);               // rangeShift
1000  tableDir[11] = (char)(t & 0xff);
1001  pos = 12;
1002  for (i = 0; i < nNewTables; ++i) {
1003    tableDir[pos   ] = (char)(newTables[i].tag >> 24);
1004    tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
1005    tableDir[pos+ 2] = (char)(newTables[i].tag >>  8);
1006    tableDir[pos+ 3] = (char) newTables[i].tag;
1007    tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
1008    tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
1009    tableDir[pos+ 6] = (char)(newTables[i].checksum >>  8);
1010    tableDir[pos+ 7] = (char) newTables[i].checksum;
1011    tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
1012    tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
1013    tableDir[pos+10] = (char)(newTables[i].offset >>  8);
1014    tableDir[pos+11] = (char) newTables[i].offset;
1015    tableDir[pos+12] = (char)(newTables[i].len >> 24);
1016    tableDir[pos+13] = (char)(newTables[i].len >> 16);
1017    tableDir[pos+14] = (char)(newTables[i].len >>  8);
1018    tableDir[pos+15] = (char) newTables[i].len;
1019    pos += 16;
1020  }
1021  (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
1022
1023  // compute the file checksum
1024  fileChecksum = computeTableChecksum((Guchar *)tableDir,
1025                                      12 + nNewTables * 16);
1026  for (i = 0; i < nNewTables; ++i) {
1027    fileChecksum += newTables[i].checksum;
1028  }
1029  fileChecksum = 0xb1b0afba - fileChecksum;
1030
1031  // write the tables
1032  for (i = 0; i < nNewTables; ++i) {
1033    if (newTables[i].tag == headTag) {
1034      if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1035        (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
1036        checksumBuf[0] = fileChecksum >> 24;
1037        checksumBuf[1] = fileChecksum >> 16;
1038        checksumBuf[2] = fileChecksum >> 8;
1039        checksumBuf[3] = fileChecksum;
1040        (*outputFunc)(outputStream, checksumBuf, 4);
1041        (*outputFunc)(outputStream,
1042                      (char *)file + newTables[i].origOffset + 12,
1043                      newTables[i].len - 12);
1044      } else {
1045        for (j = 0; j < newTables[i].len; ++j) {
1046          (*outputFunc)(outputStream, "\0", 1);
1047        }
1048      }
1049    } else if (newTables[i].tag == cmapTag && codeToGID) {
1050      (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
1051    } else if (newTables[i].tag == cmapTag && missingCmap) {
1052      (*outputFunc)(outputStream, cmapTab, newTables[i].len);
1053    } else if (newTables[i].tag == nameTag && name) {
1054      (*outputFunc)(outputStream, newNameTab, newTables[i].len);
1055    } else if (newTables[i].tag == nameTag && missingName) {
1056      (*outputFunc)(outputStream, nameTab, newTables[i].len);
1057    } else if (newTables[i].tag == postTag && missingPost) {
1058      (*outputFunc)(outputStream, postTab, newTables[i].len);
1059    } else if (newTables[i].tag == locaTag && unsortedLoca) {
1060      for (j = 0; j <= nGlyphs; ++j) {
1061        if (locaFmt) {
1062          locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
1063          locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
1064          locaBuf[2] = (char)(locaTable[j].newOffset >>  8);
1065          locaBuf[3] = (char) locaTable[j].newOffset;
1066          (*outputFunc)(outputStream, locaBuf, 4);
1067        } else {
1068          locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
1069          locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
1070          (*outputFunc)(outputStream, locaBuf, 2);
1071        }
1072      }
1073    } else if (newTables[i].tag == glyfTag && unsortedLoca) {
1074      pos = tables[seekTable("glyf")].offset;
1075      for (j = 0; j < nGlyphs; ++j) {
1076        n = locaTable[j].len;
1077        if (n > 0) {
1078          k = locaTable[j].origOffset;
1079          if (checkRegion(pos + k, n)) {
1080            (*outputFunc)(outputStream, (char *)file + pos + k, n);
1081          } else {
1082            for (k = 0; k < n; ++k) {
1083              (*outputFunc)(outputStream, "\0", 1);
1084            }
1085          }
1086          if ((k = locaTable[j].len & 3)) {
1087            (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
1088          }
1089        }
1090      }
1091    } else {
1092      if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1093        (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
1094                      newTables[i].len);
1095      } else {
1096        for (j = 0; j < newTables[i].len; ++j) {
1097          (*outputFunc)(outputStream, "\0", 1);
1098        }
1099      }
1100    }
1101    if (newTables[i].len & 3) {
1102      (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
1103    }
1104  }
1105
1106  gfree(newCmapTab);
1107  gfree(newNameTab);
1108  gfree(tableDir);
1109  gfree(newTables);
1110 done1:
1111  gfree(locaTable);
1112}
1113
1114void FoFiTrueType::cvtEncoding(char **encoding,
1115                               FoFiOutputFunc outputFunc,
1116                               void *outputStream) {
1117  char *name;
1118  char buf[64];
1119  int i;
1120
1121  (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
1122  if (encoding) {
1123    for (i = 0; i < 256; ++i) {
1124      if (!(name = encoding[i])) {
1125        name = ".notdef";
1126      }
1127      sprintf(buf, "dup %d /", i);
1128      (*outputFunc)(outputStream, buf, strlen(buf));
1129      (*outputFunc)(outputStream, name, strlen(name));
1130      (*outputFunc)(outputStream, " put\n", 5);
1131    }
1132  } else {
1133    for (i = 0; i < 256; ++i) {
1134      sprintf(buf, "dup %d /c%02x put\n", i, i);
1135      (*outputFunc)(outputStream, buf, strlen(buf));
1136    }
1137  }
1138  (*outputFunc)(outputStream, "readonly def\n", 13);
1139}
1140
1141void FoFiTrueType::cvtCharStrings(char **encoding,
1142                                  Gushort *codeToGID,
1143                                  FoFiOutputFunc outputFunc,
1144                                  void *outputStream) {
1145  char *name;
1146  char buf[64], buf2[16];
1147  int i, k;
1148
1149  // always define '.notdef'
1150  (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
1151  (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
1152
1153  // if there's no 'cmap' table, punt
1154  if (nCmaps == 0) {
1155    goto err;
1156  }
1157
1158  // map char name to glyph index:
1159  // 1. use encoding to map name to char code
1160  // 2. use codeToGID to map char code to glyph index
1161  // N.B. We do this in reverse order because font subsets can have
1162  //      weird encodings that use the same character name twice, and
1163  //      the first definition is probably the one we want.
1164  k = 0; // make gcc happy
1165  for (i = 255; i >= 0; --i) {
1166    if (encoding) {
1167      name = encoding[i];
1168    } else {
1169      sprintf(buf2, "c%02x", i);
1170      name = buf2;
1171    }
1172    if (name && strcmp(name, ".notdef")) {
1173      k = codeToGID[i];
1174      // note: Distiller (maybe Adobe's PS interpreter in general)
1175      // doesn't like TrueType fonts that have CharStrings entries
1176      // which point to nonexistent glyphs, hence the (k < nGlyphs)
1177      // test
1178      if (k > 0 && k < nGlyphs) {
1179        (*outputFunc)(outputStream, "/", 1);
1180        (*outputFunc)(outputStream, name, strlen(name));
1181        sprintf(buf, " %d def\n", k);
1182        (*outputFunc)(outputStream, buf, strlen(buf));
1183      }
1184    }
1185  }
1186
1187 err:
1188  (*outputFunc)(outputStream, "end readonly def\n", 17);
1189}
1190
1191void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
1192                            void *outputStream, GooString *name,
1193                            GBool needVerticalMetrics) {
1194  Guchar headData[54];
1195  TrueTypeLoca *locaTable;
1196  Guchar *locaData;
1197  TrueTypeTable newTables[nT42Tables];
1198  Guchar tableDir[12 + nT42Tables*16];
1199  GBool ok;
1200  Guint checksum;
1201  int nNewTables;
1202  int length, pos, glyfPos, i, j, k;
1203  Guchar vheaTab[36] = {
1204    0, 1, 0, 0,                 // table version number
1205    0, 0,                       // ascent
1206    0, 0,                       // descent
1207    0, 0,                       // reserved
1208    0, 0,                       // max advance height
1209    0, 0,                       // min top side bearing
1210    0, 0,                       // min bottom side bearing
1211    0, 0,                       // y max extent
1212    0, 0,                       // caret slope rise
1213    0, 1,                       // caret slope run
1214    0, 0,                       // caret offset
1215    0, 0,                       // reserved
1216    0, 0,                       // reserved
1217    0, 0,                       // reserved
1218    0, 0,                       // reserved
1219    0, 0,                       // metric data format
1220    0, 1                        // number of advance heights in vmtx table
1221  };
1222  Guchar *vmtxTab;
1223  GBool needVhea, needVmtx;
1224  int advance;
1225
1226  // construct the 'head' table, zero out the font checksum
1227  i = seekTable("head");
1228  pos = tables[i].offset;
1229  if (!checkRegion(pos, 54)) {
1230    return;
1231  }
1232  memcpy(headData, file + pos, 54);
1233  headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
1234
1235  // read the original 'loca' table, pad entries out to 4 bytes, and
1236  // sort it into proper order -- some (non-compliant) fonts have
1237  // out-of-order loca tables; in order to correctly handle the case
1238  // where (compliant) fonts have empty entries in the middle of the
1239  // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
1240  // and idx as its secondary key (ensuring that adjacent entries with
1241  // the same pos value remain in the same order)
1242  locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
1243  i = seekTable("loca");
1244  pos = tables[i].offset;
1245  ok = gTrue;
1246  for (i = 0; i <= nGlyphs; ++i) {
1247    locaTable[i].idx = i;
1248    if (locaFmt) {
1249      locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
1250    } else {
1251      locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
1252    }
1253  }
1254  qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1255        &cmpTrueTypeLocaOffset);
1256  for (i = 0; i < nGlyphs; ++i) {
1257    locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
1258  }
1259  locaTable[nGlyphs].len = 0;
1260  qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1261        &cmpTrueTypeLocaIdx);
1262  pos = 0;
1263  for (i = 0; i <= nGlyphs; ++i) {
1264    locaTable[i].newOffset = pos;
1265    pos += locaTable[i].len;
1266    if (pos & 3) {
1267      pos += 4 - (pos & 3);
1268    }
1269  }
1270
1271  // construct the new 'loca' table
1272  locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
1273  for (i = 0; i <= nGlyphs; ++i) {
1274    pos = locaTable[i].newOffset;
1275    if (locaFmt) {
1276      locaData[4*] = (Guchar)(pos >> 24);
1277      locaData[4*i+1] = (Guchar)(pos >> 16);
1278      locaData[4*i+2] = (Guchar)(pos >>  8);
1279      locaData[4*i+3] = (Guchar) pos;
1280    } else {
1281      locaData[2*] = (Guchar)(pos >> 9);
1282      locaData[2*i+1] = (Guchar)(pos >> 1);
1283    }
1284  }
1285
1286  // count the number of tables
1287  nNewTables = 0;
1288  for (i = 0; i < nT42Tables; ++i) {
1289    if (t42Tables[i].required ||
1290        seekTable(t42Tables[i].tag) >= 0) {
1291      ++nNewTables;
1292    }
1293  }
1294  vmtxTab = NULL; // make gcc happy
1295  advance = 0; // make gcc happy
1296  if (needVerticalMetrics) {
1297    needVhea = seekTable("vhea") < 0;
1298    needVmtx = seekTable("vmtx") < 0;
1299    if (needVhea || needVmtx) {
1300      i = seekTable("head");
1301      advance = getU16BE(tables[i].offset + 18, &ok); // units per em
1302      if (needVhea) {
1303        ++nNewTables;
1304      }
1305      if (needVmtx) {
1306        ++nNewTables;
1307      }
1308    }
1309  }
1310
1311  // construct the new table headers, including table checksums
1312  // (pad each table out to a multiple of 4 bytes)
1313  pos = 12 + nNewTables*16;
1314  k = 0;
1315  for (i = 0; i < nT42Tables; ++i) {
1316    length = -1;
1317    checksum = 0; // make gcc happy
1318    if (i == t42HeadTable) {
1319      length = 54;
1320      checksum = computeTableChecksum(headData, 54);
1321    } else if (i == t42LocaTable) {
1322      length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1323      checksum = computeTableChecksum(locaData, length);
1324    } else if (i == t42GlyfTable) {
1325      length = 0;
1326      checksum = 0;
1327      glyfPos = tables[seekTable("glyf")].offset;
1328      for (j = 0; j < nGlyphs; ++j) {
1329        length += locaTable[j].len;
1330        if (length & 3) {
1331          length += 4 - (length & 3);
1332        }
1333        if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1334          checksum +=
1335              computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
1336                                   locaTable[j].len);
1337        }
1338      }
1339    } else {
1340      if ((j = seekTable(t42Tables[i].tag)) >= 0) {
1341        length = tables[j].len;
1342        if (checkRegion(tables[j].offset, length)) {
1343          checksum = computeTableChecksum(file + tables[j].offset, length);
1344        }
1345      } else if (needVerticalMetrics && i == t42VheaTable) {
1346        vheaTab[10] = advance / 256;    // max advance height
1347        vheaTab[11] = advance % 256;
1348        length = sizeof(vheaTab);
1349        checksum = computeTableChecksum(vheaTab, length);
1350      } else if (needVerticalMetrics && i == t42VmtxTable) {
1351        length = 4 + (nGlyphs - 1) * 4;
1352        vmtxTab = (Guchar *)gmalloc(length);
1353        vmtxTab[0] = advance / 256;
1354        vmtxTab[1] = advance % 256;
1355        for (j = 2; j < length; j += 2) {
1356          vmtxTab[j] = 0;
1357          vmtxTab[j+1] = 0;
1358        }
1359        checksum = computeTableChecksum(vmtxTab, length);
1360      } else if (t42Tables[i].required) {
1361        //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1362        //~       t42Tables[i].tag);
1363        length = 0;
1364        checksum = 0;
1365      }
1366    }
1367    if (length >= 0) {
1368      newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
1369                         ((t42Tables[i].tag[1] & 0xff) << 16) |
1370                         ((t42Tables[i].tag[2] & 0xff) <<  8) |
1371                          (t42Tables[i].tag[3] & 0xff);
1372      newTables[k].checksum = checksum;
1373      newTables[k].offset = pos;
1374      newTables[k].len = length;
1375      pos += length;
1376      if (pos & 3) {
1377        pos += 4 - (length & 3);
1378      }
1379      ++k;
1380    }
1381  }
1382
1383  // construct the table directory
1384  tableDir[0] = 0x00;           // sfnt version
1385  tableDir[1] = 0x01;
1386  tableDir[2] = 0x00;
1387  tableDir[3] = 0x00;
1388  tableDir[4] = 0;              // numTables
1389  tableDir[5] = nNewTables;
1390  tableDir[6] = 0;              // searchRange
1391  tableDir[7] = (Guchar)128;
1392  tableDir[8] = 0;              // entrySelector
1393  tableDir[9] = 3;
1394  tableDir[10] = 0;             // rangeShift
1395  tableDir[11] = (Guchar)(16 * nNewTables - 128);
1396  pos = 12;
1397  for (i = 0; i < nNewTables; ++i) {
1398    tableDir[pos   ] = (Guchar)(newTables[i].tag >> 24);
1399    tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
1400    tableDir[pos+ 2] = (Guchar)(newTables[i].tag >>  8);
1401    tableDir[pos+ 3] = (Guchar) newTables[i].tag;
1402    tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
1403    tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
1404    tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >>  8);
1405    tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
1406    tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
1407    tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
1408    tableDir[pos+10] = (Guchar)(newTables[i].offset >>  8);
1409    tableDir[pos+11] = (Guchar) newTables[i].offset;
1410    tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
1411    tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
1412    tableDir[pos+14] = (Guchar)(newTables[i].len >>  8);
1413    tableDir[pos+15] = (Guchar) newTables[i].len;
1414    pos += 16;
1415  }
1416
1417  // compute the font checksum and store it in the head table
1418  checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
1419  for (i = 0; i < nNewTables; ++i) {
1420    checksum += newTables[i].checksum;
1421  }
1422  checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
1423  headData[ 8] = (Guchar)(checksum >> 24);
1424  headData[ 9] = (Guchar)(checksum >> 16);
1425  headData[10] = (Guchar)(checksum >>  8);
1426  headData[11] = (Guchar) checksum;
1427
1428  // start the sfnts array
1429  if (name) {
1430    (*outputFunc)(outputStream, "/", 1);
1431    (*outputFunc)(outputStream, name->getCString(), name->getLength());
1432    (*outputFunc)(outputStream, " [\n", 3);
1433  } else {
1434    (*outputFunc)(outputStream, "/sfnts [\n", 9);
1435  }
1436
1437  // write the table directory
1438  dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
1439
1440  // write the tables
1441  for (i = 0; i < nNewTables; ++i) {
1442    if (i == t42HeadTable) {
1443      dumpString(headData, 54, outputFunc, outputStream);
1444    } else if (i == t42LocaTable) {
1445      length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1446      dumpString(locaData, length, outputFunc, outputStream);
1447    } else if (i == t42GlyfTable) {
1448      glyfPos = tables[seekTable("glyf")].offset;
1449      for (j = 0; j < nGlyphs; ++j) {
1450        if (locaTable[j].len > 0 &&
1451            checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1452          dumpString(file + glyfPos + locaTable[j].origOffset,
1453                     locaTable[j].len, outputFunc, outputStream);
1454        }
1455      }
1456    } else {
1457      // length == 0 means the table is missing and the error was
1458      // already reported during the construction of the table
1459      // headers
1460      if ((length = newTables[i].len) > 0) {
1461        if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
1462            checkRegion(tables[j].offset, tables[j].len)) {
1463          dumpString(file + tables[j].offset, tables[j].len,
1464                     outputFunc, outputStream);
1465        } else if (needVerticalMetrics && i == t42VheaTable) {
1466          dumpString(vheaTab, length, outputFunc, outputStream);
1467        } else if (needVerticalMetrics && i == t42VmtxTable) {
1468          dumpString(vmtxTab, length, outputFunc, outputStream);
1469          gfree(vmtxTab);
1470        }
1471      }
1472    }
1473  }
1474
1475  // end the sfnts array
1476  (*outputFunc)(outputStream, "] def\n", 6);
1477
1478  gfree(locaData);
1479  gfree(locaTable);
1480}
1481
1482void FoFiTrueType::dumpString(Guchar *s, int length,
1483                              FoFiOutputFunc outputFunc,
1484                              void *outputStream) {
1485  char buf[64];
1486  int pad, i, j;
1487
1488  (*outputFunc)(outputStream, "<", 1);
1489  for (i = 0; i < length; i += 32) {
1490    for (j = 0; j < 32 && i+j < length; ++j) {
1491      sprintf(buf, "%02X", s[i+j] & 0xff);
1492      (*outputFunc)(outputStream, buf, strlen(buf));
1493    }
1494    if (i % (65536 - 32) == 65536 - 64) {
1495      (*outputFunc)(outputStream, ">\n<", 3);
1496    } else if (i+32 < length) {
1497      (*outputFunc)(outputStream, "\n", 1);
1498    }
1499  }
1500  if (length & 3) {
1501    pad = 4 - (length & 3);
1502    for (i = 0; i < pad; ++i) {
1503      (*outputFunc)(outputStream, "00", 2);
1504    }
1505  }
1506  // add an extra zero byte because the Adobe Type 42 spec says so
1507  (*outputFunc)(outputStream, "00>\n", 4);
1508}
1509
1510Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
1511  Guint checksum, word;
1512  int i;
1513
1514  checksum = 0;
1515  for (i = 0; i+3 < length; i += 4) {
1516    word = ((data[] & 0xff) << 24) +
1517           ((data[i+1] & 0xff) << 16) +
1518           ((data[i+2] & 0xff) <<  8) +
1519            (data[i+3] & 0xff);
1520    checksum += word;
1521  }
1522  if (length & 3) {
1523    word = 0;
1524    i = length & ~3;
1525    switch (length & 3) {
1526    case 3:
1527      word |= (data[i+2] & 0xff) <<  8;
1528    case 2:
1529      word |= (data[i+1] & 0xff) << 16;
1530    case 1:
1531      word |= (data[] & 0xff) << 24;
1532      break;
1533    }
1534    checksum += word;
1535  }
1536  return checksum;
1537}
1538
1539#define toTag(a,b,c,d) (((unsigned int)(a)<<24) | ((unsigned int)(b)<<16) | ((unsigned int)(c)<<8) | (d))
1540
1541void FoFiTrueType::parse() {
1542  Guint topTag;
1543  int pos, i, j;
1544  unsigned int head;
1545
1546  parsedOk = gTrue;
1547
1548  // look for a collection (TTC)
1549  topTag = getU32BE(0, &parsedOk);
1550  if (!parsedOk) {
1551    return;
1552  }
1553  if (topTag == ttcfTag) {
1554    pos = getU32BE(12, &parsedOk);
1555    if (!parsedOk) {
1556      return;
1557    }
1558  } else {
1559    pos = 0;
1560  }
1561
1562  // read the table directory
1563  head = getU32BE(pos, &parsedOk);
1564  if (! parsedOk)
1565    return;
1566  if (head == toTag('t','t','c','f')) {
1567    /* TTC font */
1568    unsigned int tableDir;
1569    int dircount;
1570
1571    dircount = getU32BE(8, &parsedOk);
1572    if (!parsedOk)
1573      return;
1574    if (! dircount) {
1575      parsedOk = gFalse;
1576      return;
1577    }
1578
1579    if (faceIndex >= dircount)
1580      faceIndex = 0;
1581    pos = getU32BE(12 + faceIndex * 4, &parsedOk);
1582    if (! parsedOk)
1583      return;
1584  }
1585
1586  pos += 4;
1587  nTables = getU16BE(pos, &parsedOk);
1588  if (!parsedOk) {
1589    return;
1590  }
1591
1592  pos += 8;
1593  tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
1594  for (i = 0; i < nTables; ++i) {
1595    tables[i].tag = getU32BE(pos, &parsedOk);
1596    tables[i].checksum = getU32BE(pos + 4, &parsedOk);
1597    tables[i].offset = (int)getU32BE(pos + 8, &parsedOk);
1598    tables[i].len = (int)getU32BE(pos + 12, &parsedOk);
1599    if (tables[i].offset + tables[i].len < tables[i].offset ||
1600        tables[i].offset + tables[i].len > len) {
1601      parsedOk = gFalse;
1602    }
1603    pos += 16;
1604  }
1605  if (!parsedOk) {
1606    return;
1607  }
1608
1609  // check for tables that are required by both the TrueType spec and
1610  // the Type 42 spec
1611  if (seekTable("head") < 0 ||
1612      seekTable("hhea") < 0 ||
1613      seekTable("loca") < 0 ||
1614      seekTable("maxp") < 0 ||
1615      seekTable("glyf") < 0 ||
1616      seekTable("hmtx") < 0) {
1617    parsedOk = gFalse;
1618    return;
1619  }
1620
1621  // read the cmaps
1622  if ((i = seekTable("cmap")) >= 0) {
1623    pos = tables[i].offset + 2;
1624    nCmaps = getU16BE(pos, &parsedOk);
1625    pos += 2;
1626    if (!parsedOk) {
1627      return;
1628    }
1629    cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
1630    for (j = 0; j < nCmaps; ++j) {
1631      cmaps[j].platform = getU16BE(pos, &parsedOk);
1632      cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
1633      cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
1634      pos += 8;
1635      cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
1636      cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
1637    }
1638    if (!parsedOk) {
1639      return;
1640    }
1641  } else {
1642    nCmaps = 0;
1643  }
1644
1645  // get the number of glyphs from the maxp table
1646  i = seekTable("maxp");
1647  nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
1648  if (!parsedOk) {
1649    return;
1650  }
1651
1652  // get the bbox and loca table format from the head table
1653  i = seekTable("head");
1654  bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
1655  bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
1656  bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
1657  bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
1658  locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
1659  if (!parsedOk) {
1660    return;
1661  }
1662
1663  // make sure the loca table is sane (correct length and entries are
1664  // in bounds)
1665  i = seekTable("loca");
1666  if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
1667    parsedOk = gFalse;
1668    return;
1669  }
1670  for (j = 0; j <= nGlyphs; ++j) {
1671    if (locaFmt) {
1672      pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
1673    } else {
1674      pos = getU16BE(tables[i].offset + j*2, &parsedOk);
1675    }
1676    if (pos < 0 || pos > len) {
1677      parsedOk = gFalse;
1678    }
1679  }
1680  if (!parsedOk) {
1681    return;
1682  }
1683
1684  // read the post table
1685  readPostTable();
1686}
1687
1688void FoFiTrueType::readPostTable() {
1689  GooString *name;
1690  int tablePos, postFmt, stringIdx, stringPos;
1691  GBool ok;
1692  int i, j, n, m;
1693
1694  ok = gTrue;
1695  if ((i = seekTable("post")) < 0) {
1696    return;
1697  }
1698  tablePos = tables[i].offset;
1699  postFmt = getU32BE(tablePos, &ok);
1700  if (!ok) {
1701    goto err;
1702  }
1703  if (postFmt == 0x00010000) {
1704    nameToGID = new GooHash(gTrue);
1705    for (i = 0; i < 258; ++i) {
1706      nameToGID->add(new GooString(macGlyphNames[i]), i);
1707    }
1708  } else if (postFmt == 0x00020000) {
1709    nameToGID = new GooHash(gTrue);
1710    n = getU16BE(tablePos + 32, &ok);
1711    if (!ok) {
1712      goto err;
1713    }
1714    if (n > nGlyphs) {
1715      n = nGlyphs;
1716    }
1717    stringIdx = 0;
1718    stringPos = tablePos + 34 + 2*n;
1719    for (i = 0; i < n; ++i) {
1720      j = getU16BE(tablePos + 34 + 2*i, &ok);
1721      if (j < 258) {
1722        nameToGID->removeInt(macGlyphNames[j]);
1723        nameToGID->add(new GooString(macGlyphNames[j]), i);
1724      } else {
1725        j -= 258;
1726        if (j != stringIdx) {
1727          for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
1728               stringIdx < j;
1729               ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
1730          if (!ok) {
1731            goto err;
1732          }
1733        }
1734        m = getU8(stringPos, &ok);
1735        if (!ok || !checkRegion(stringPos + 1, m)) {
1736          goto err;
1737        }
1738        name = new GooString((char *)&file[stringPos + 1], m);
1739        nameToGID->removeInt(name);
1740        nameToGID->add(name, i);
1741        ++stringIdx;
1742        stringPos += 1 + m;
1743      }
1744    }
1745  } else if (postFmt == 0x00028000) {
1746    nameToGID = new GooHash(gTrue);
1747    for (i = 0; i < nGlyphs; ++i) {
1748      j = getU8(tablePos + 32 + i, &ok);
1749      if (!ok) {
1750        goto err;
1751      }
1752      if (j < 258) {
1753        nameToGID->removeInt(macGlyphNames[j]);
1754        nameToGID->add(new GooString(macGlyphNames[j]), i);
1755      }
1756    }
1757  }
1758
1759  return;
1760
1761 err:
1762  if (nameToGID) {
1763    delete nameToGID;
1764    nameToGID = NULL;
1765  }
1766}
1767
1768int FoFiTrueType::seekTable(char *tag) {
1769  Guint tagI;
1770  int i;
1771
1772  tagI = ((tag[0] & 0xff) << 24) |
1773         ((tag[1] & 0xff) << 16) |
1774         ((tag[2] & 0xff) << 8) |
1775          (tag[3] & 0xff);
1776  for (i = 0; i < nTables; ++i) {
1777    if (tables[i].tag == tagI) {
1778      return i;
1779    }
1780  }
1781  return -1;
1782}
Note: See TracBrowser for help on using the repository browser.