modified makefile to allow easier adjustment of build options for different targets...
[AROS-Contrib.git] / arospdf / fofi / FoFiTrueType.cc
blobe8add984292b4bf9794e473938edaec58e069bb4
1 //========================================================================
2 //
3 // FoFiTrueType.cc
4 //
5 // Copyright 1999-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
9 #include <aconf.h>
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
15 #include <stdlib.h>
16 #include <string.h>
17 #include "gtypes.h"
18 #include "gmem.h"
19 #include "GString.h"
20 #include "GHash.h"
21 #include "FoFiType1C.h"
22 #include "FoFiTrueType.h"
25 // Terminology
26 // -----------
28 // character code = number used as an element of a text string
30 // character name = glyph name = name for a particular glyph within a
31 // font
33 // glyph index = GID = position (within some internal table in the font)
34 // where the instructions to draw a particular glyph are
35 // stored
37 // Type 1 fonts
38 // ------------
40 // Type 1 fonts contain:
42 // Encoding: array of glyph names, maps char codes to glyph names
44 // Encoding[charCode] = charName
46 // CharStrings: dictionary of instructions, keyed by character names,
47 // maps character name to glyph data
49 // CharStrings[charName] = glyphData
51 // TrueType fonts
52 // --------------
54 // TrueType fonts contain:
56 // 'cmap' table: mapping from character code to glyph index; there may
57 // be multiple cmaps in a TrueType font
59 // cmap[charCode] = gid
61 // 'post' table: mapping from glyph index to glyph name
63 // post[gid] = glyphName
65 // Type 42 fonts
66 // -------------
68 // Type 42 fonts contain:
70 // Encoding: array of glyph names, maps char codes to glyph names
72 // Encoding[charCode] = charName
74 // CharStrings: dictionary of glyph indexes, keyed by character names,
75 // maps character name to glyph index
77 // CharStrings[charName] = gid
80 //------------------------------------------------------------------------
82 #define ttcfTag 0x74746366
84 //------------------------------------------------------------------------
86 struct TrueTypeTable {
87 Guint tag;
88 Guint checksum;
89 int offset;
90 int origOffset;
91 int len;
94 struct TrueTypeCmap {
95 int platform;
96 int encoding;
97 int offset;
98 int len;
99 int fmt;
102 struct TrueTypeLoca {
103 int idx;
104 int origOffset;
105 int newOffset;
106 int len;
109 #define cmapTag 0x636d6170
110 #define glyfTag 0x676c7966
111 #define headTag 0x68656164
112 #define hheaTag 0x68686561
113 #define hmtxTag 0x686d7478
114 #define locaTag 0x6c6f6361
115 #define nameTag 0x6e616d65
116 #define os2Tag 0x4f532f32
117 #define postTag 0x706f7374
119 static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
120 TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
121 TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
123 if (loca1->origOffset == loca2->origOffset) {
124 return loca1->idx - loca2->idx;
126 return loca1->origOffset - loca2->origOffset;
129 static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
130 TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
131 TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
133 return loca1->idx - loca2->idx;
136 static int cmpTrueTypeTableTag(const void *p1, const void *p2) {
137 TrueTypeTable *tab1 = (TrueTypeTable *)p1;
138 TrueTypeTable *tab2 = (TrueTypeTable *)p2;
140 return (int)tab1->tag - (int)tab2->tag;
143 //------------------------------------------------------------------------
145 struct T42Table {
146 char *tag; // 4-byte tag
147 GBool required; // required by the TrueType spec?
150 // TrueType tables to be embedded in Type 42 fonts.
151 // NB: the table names must be in alphabetical order here.
152 #define nT42Tables 11
153 static T42Table t42Tables[nT42Tables] = {
154 { "cvt ", gTrue },
155 { "fpgm", gTrue },
156 { "glyf", gTrue },
157 { "head", gTrue },
158 { "hhea", gTrue },
159 { "hmtx", gTrue },
160 { "loca", gTrue },
161 { "maxp", gTrue },
162 { "prep", gTrue },
163 { "vhea", gFalse },
164 { "vmtx", gFalse }
166 #define t42HeadTable 3
167 #define t42LocaTable 6
168 #define t42GlyfTable 2
169 #define t42VheaTable 9
170 #define t42VmtxTable 10
172 //------------------------------------------------------------------------
174 // Glyph names in some arbitrary standard order that Apple uses for
175 // their TrueType fonts.
176 static const char *macGlyphNames[258] = {
177 ".notdef", "null", "CR", "space",
178 "exclam", "quotedbl", "numbersign", "dollar",
179 "percent", "ampersand", "quotesingle", "parenleft",
180 "parenright", "asterisk", "plus", "comma",
181 "hyphen", "period", "slash", "zero",
182 "one", "two", "three", "four",
183 "five", "six", "seven", "eight",
184 "nine", "colon", "semicolon", "less",
185 "equal", "greater", "question", "at",
186 "A", "B", "C", "D",
187 "E", "F", "G", "H",
188 "I", "J", "K", "L",
189 "M", "N", "O", "P",
190 "Q", "R", "S", "T",
191 "U", "V", "W", "X",
192 "Y", "Z", "bracketleft", "backslash",
193 "bracketright", "asciicircum", "underscore", "grave",
194 "a", "b", "c", "d",
195 "e", "f", "g", "h",
196 "i", "j", "k", "l",
197 "m", "n", "o", "p",
198 "q", "r", "s", "t",
199 "u", "v", "w", "x",
200 "y", "z", "braceleft", "bar",
201 "braceright", "asciitilde", "Adieresis", "Aring",
202 "Ccedilla", "Eacute", "Ntilde", "Odieresis",
203 "Udieresis", "aacute", "agrave", "acircumflex",
204 "adieresis", "atilde", "aring", "ccedilla",
205 "eacute", "egrave", "ecircumflex", "edieresis",
206 "iacute", "igrave", "icircumflex", "idieresis",
207 "ntilde", "oacute", "ograve", "ocircumflex",
208 "odieresis", "otilde", "uacute", "ugrave",
209 "ucircumflex", "udieresis", "dagger", "degree",
210 "cent", "sterling", "section", "bullet",
211 "paragraph", "germandbls", "registered", "copyright",
212 "trademark", "acute", "dieresis", "notequal",
213 "AE", "Oslash", "infinity", "plusminus",
214 "lessequal", "greaterequal", "yen", "mu1",
215 "partialdiff", "summation", "product", "pi",
216 "integral", "ordfeminine", "ordmasculine", "Ohm",
217 "ae", "oslash", "questiondown", "exclamdown",
218 "logicalnot", "radical", "florin", "approxequal",
219 "increment", "guillemotleft", "guillemotright", "ellipsis",
220 "nbspace", "Agrave", "Atilde", "Otilde",
221 "OE", "oe", "endash", "emdash",
222 "quotedblleft", "quotedblright", "quoteleft", "quoteright",
223 "divide", "lozenge", "ydieresis", "Ydieresis",
224 "fraction", "currency", "guilsinglleft", "guilsinglright",
225 "fi", "fl", "daggerdbl", "periodcentered",
226 "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
227 "Ecircumflex", "Aacute", "Edieresis", "Egrave",
228 "Iacute", "Icircumflex", "Idieresis", "Igrave",
229 "Oacute", "Ocircumflex", "applelogo", "Ograve",
230 "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
231 "circumflex", "tilde", "overscore", "breve",
232 "dotaccent", "ring", "cedilla", "hungarumlaut",
233 "ogonek", "caron", "Lslash", "lslash",
234 "Scaron", "scaron", "Zcaron", "zcaron",
235 "brokenbar", "Eth", "eth", "Yacute",
236 "yacute", "Thorn", "thorn", "minus",
237 "multiply", "onesuperior", "twosuperior", "threesuperior",
238 "onehalf", "onequarter", "threequarters", "franc",
239 "Gbreve", "gbreve", "Idot", "Scedilla",
240 "scedilla", "Cacute", "cacute", "Ccaron",
241 "ccaron", "dmacron"
244 //------------------------------------------------------------------------
245 // FoFiTrueType
246 //------------------------------------------------------------------------
248 FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) {
249 FoFiTrueType *ff;
251 ff = new FoFiTrueType(fileA, lenA, gFalse);
252 if (!ff->parsedOk) {
253 delete ff;
254 return NULL;
256 return ff;
259 FoFiTrueType *FoFiTrueType::load(char *fileName) {
260 FoFiTrueType *ff;
261 char *fileA;
262 int lenA;
264 if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
265 return NULL;
267 ff = new FoFiTrueType(fileA, lenA, gTrue);
268 if (!ff->parsedOk) {
269 delete ff;
270 return NULL;
272 return ff;
275 FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA):
276 FoFiBase(fileA, lenA, freeFileDataA)
278 tables = NULL;
279 nTables = 0;
280 cmaps = NULL;
281 nCmaps = 0;
282 nameToGID = NULL;
283 parsedOk = gFalse;
285 parse();
288 FoFiTrueType::~FoFiTrueType() {
289 gfree(tables);
290 gfree(cmaps);
291 if (nameToGID) {
292 delete nameToGID;
296 int FoFiTrueType::getNumCmaps() {
297 return nCmaps;
300 int FoFiTrueType::getCmapPlatform(int i) {
301 return cmaps[i].platform;
304 int FoFiTrueType::getCmapEncoding(int i) {
305 return cmaps[i].encoding;
308 int FoFiTrueType::findCmap(int platform, int encoding) {
309 int i;
311 for (i = 0; i < nCmaps; ++i) {
312 if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
313 return i;
316 return -1;
319 Gushort FoFiTrueType::mapCodeToGID(int i, int c) {
320 Gushort gid;
321 int segCnt, segEnd, segStart, segDelta, segOffset;
322 int cmapFirst, cmapLen;
323 int pos, a, b, m;
324 GBool ok;
326 if (i < 0 || i >= nCmaps) {
327 return 0;
329 ok = gTrue;
330 pos = cmaps[i].offset;
331 switch (cmaps[i].fmt) {
332 case 0:
333 if (c < 0 || c >= cmaps[i].len - 6) {
334 return 0;
336 gid = getU8(cmaps[i].offset + 6 + c, &ok);
337 break;
338 case 4:
339 segCnt = getU16BE(pos + 6, &ok) / 2;
340 a = -1;
341 b = segCnt - 1;
342 segEnd = getU16BE(pos + 14 + 2*b, &ok);
343 if (c > segEnd) {
344 // malformed font -- the TrueType spec requires the last segEnd
345 // to be 0xffff
346 return 0;
348 // invariant: seg[a].end < code <= seg[b].end
349 while (b - a > 1 && ok) {
350 m = (a + b) / 2;
351 segEnd = getU16BE(pos + 14 + 2*m, &ok);
352 if (segEnd < c) {
353 a = m;
354 } else {
355 b = m;
358 segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
359 segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
360 segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
361 if (c < segStart) {
362 return 0;
364 if (segOffset == 0) {
365 gid = (c + segDelta) & 0xffff;
366 } else {
367 gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
368 segOffset + 2 * (c - segStart), &ok);
369 if (gid != 0) {
370 gid = (gid + segDelta) & 0xffff;
373 break;
374 case 6:
375 cmapFirst = getU16BE(pos + 6, &ok);
376 cmapLen = getU16BE(pos + 8, &ok);
377 if (c < cmapFirst || c >= cmapFirst + cmapLen) {
378 return 0;
380 gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
381 break;
382 default:
383 return 0;
385 if (!ok) {
386 return 0;
388 return gid;
391 int FoFiTrueType::mapNameToGID(char *name) {
392 if (!nameToGID) {
393 return 0;
395 return nameToGID->lookupInt((char *)name);
398 Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) {
399 FoFiType1C *ff;
400 Gushort *map;
401 int i;
403 *nCIDs = 0;
404 if (!openTypeCFF) {
405 return NULL;
407 i = seekTable("CFF ");
408 if (!checkRegion(tables[i].offset, tables[i].len)) {
409 return NULL;
411 if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
412 tables[i].len))) {
413 return NULL;
415 map = ff->getCIDToGIDMap(nCIDs);
416 delete ff;
417 return map;
420 int FoFiTrueType::getEmbeddingRights() {
421 int i, fsType;
422 GBool ok;
424 if ((i = seekTable("OS/2")) < 0) {
425 return 4;
427 ok = gTrue;
428 fsType = getU16BE(tables[i].offset + 8, &ok);
429 if (!ok) {
430 return 4;
432 if (fsType & 0x0008) {
433 return 2;
435 if (fsType & 0x0004) {
436 return 1;
438 if (fsType & 0x0002) {
439 return 0;
441 return 3;
444 void FoFiTrueType::convertToType42(char *psName, char **encoding,
445 Gushort *codeToGID,
446 FoFiOutputFunc outputFunc,
447 void *outputStream) {
448 GString *buf;
449 GBool ok;
451 if (openTypeCFF) {
452 return;
455 // write the header
456 ok = gTrue;
457 buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n",
458 (double)getS32BE(0, &ok) / 65536.0);
459 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
460 delete buf;
462 // begin the font dictionary
463 (*outputFunc)(outputStream, "10 dict begin\n", 14);
464 (*outputFunc)(outputStream, "/FontName /", 11);
465 (*outputFunc)(outputStream, psName, strlen(psName));
466 (*outputFunc)(outputStream, " def\n", 5);
467 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
468 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
469 buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
470 bbox[0], bbox[1], bbox[2], bbox[3]);
471 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
472 delete buf;
473 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
475 // write the guts of the dictionary
476 cvtEncoding(encoding, outputFunc, outputStream);
477 cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
478 cvtSfnts(outputFunc, outputStream, NULL, gFalse);
480 // end the dictionary and define the font
481 (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
484 void FoFiTrueType::convertToType1(char *psName, char **newEncoding,
485 GBool ascii, FoFiOutputFunc outputFunc,
486 void *outputStream) {
487 FoFiType1C *ff;
488 int i;
490 if (!openTypeCFF) {
491 return;
493 i = seekTable("CFF ");
494 if (!checkRegion(tables[i].offset, tables[i].len)) {
495 return;
497 if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
498 tables[i].len))) {
499 return;
501 ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream);
502 delete ff;
505 void FoFiTrueType::convertToCIDType2(char *psName,
506 Gushort *cidMap, int nCIDs,
507 GBool needVerticalMetrics,
508 FoFiOutputFunc outputFunc,
509 void *outputStream) {
510 GString *buf;
511 Gushort cid;
512 GBool ok;
513 int i, j, k;
515 if (openTypeCFF) {
516 return;
519 // write the header
520 ok = gTrue;
521 buf = GString::format("%!PS-TrueTypeFont-{0:2g}\n",
522 (double)getS32BE(0, &ok) / 65536.0);
523 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
524 delete buf;
526 // begin the font dictionary
527 (*outputFunc)(outputStream, "20 dict begin\n", 14);
528 (*outputFunc)(outputStream, "/CIDFontName /", 14);
529 (*outputFunc)(outputStream, psName, strlen(psName));
530 (*outputFunc)(outputStream, " def\n", 5);
531 (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
532 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
533 (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
534 (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
535 (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
536 (*outputFunc)(outputStream, " /Supplement 0 def\n", 20);
537 (*outputFunc)(outputStream, " end def\n", 10);
538 (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
539 if (cidMap) {
540 buf = GString::format("/CIDCount {0:d} def\n", nCIDs);
541 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
542 delete buf;
543 if (nCIDs > 32767) {
544 (*outputFunc)(outputStream, "/CIDMap [", 9);
545 for (i = 0; i < nCIDs; i += 32768 - 16) {
546 (*outputFunc)(outputStream, "<\n", 2);
547 for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
548 (*outputFunc)(outputStream, " ", 2);
549 for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
550 cid = cidMap[i+j+k];
551 buf = GString::format("{0:02x}{1:02x}",
552 (cid >> 8) & 0xff, cid & 0xff);
553 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
554 delete buf;
556 (*outputFunc)(outputStream, "\n", 1);
558 (*outputFunc)(outputStream, " >", 3);
560 (*outputFunc)(outputStream, "\n", 1);
561 (*outputFunc)(outputStream, "] def\n", 6);
562 } else {
563 (*outputFunc)(outputStream, "/CIDMap <\n", 10);
564 for (i = 0; i < nCIDs; i += 16) {
565 (*outputFunc)(outputStream, " ", 2);
566 for (j = 0; j < 16 && i+j < nCIDs; ++j) {
567 cid = cidMap[i+j];
568 buf = GString::format("{0:02x}{1:02x}",
569 (cid >> 8) & 0xff, cid & 0xff);
570 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
571 delete buf;
573 (*outputFunc)(outputStream, "\n", 1);
575 (*outputFunc)(outputStream, "> def\n", 6);
577 } else {
578 // direct mapping - just fill the string(s) with s[i]=i
579 buf = GString::format("/CIDCount {0:d} def\n", nGlyphs);
580 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
581 delete buf;
582 if (nGlyphs > 32767) {
583 (*outputFunc)(outputStream, "/CIDMap [\n", 10);
584 for (i = 0; i < nGlyphs; i += 32767) {
585 j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
586 buf = GString::format(" {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1);
587 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
588 delete buf;
589 buf = GString::format(" 2 copy dup 2 mul exch {0:d} add -8 bitshift put\n",
591 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
592 delete buf;
593 buf = GString::format(" 1 index exch dup 2 mul 1 add exch {0:d} add"
594 " 255 and put\n", i);
595 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
596 delete buf;
597 (*outputFunc)(outputStream, " } for\n", 8);
599 (*outputFunc)(outputStream, "] def\n", 6);
600 } else {
601 buf = GString::format("/CIDMap {0:d} string\n", 2 * nGlyphs);
602 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
603 delete buf;
604 buf = GString::format(" 0 1 {0:d} {{\n", nGlyphs - 1);
605 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
606 delete buf;
607 (*outputFunc)(outputStream,
608 " 2 copy dup 2 mul exch -8 bitshift put\n", 42);
609 (*outputFunc)(outputStream,
610 " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
611 (*outputFunc)(outputStream, " } for\n", 8);
612 (*outputFunc)(outputStream, "def\n", 4);
615 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
616 buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
617 bbox[0], bbox[1], bbox[2], bbox[3]);
618 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
619 delete buf;
620 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
621 (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
622 (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
623 (*outputFunc)(outputStream, " /.notdef 0 def\n", 17);
624 (*outputFunc)(outputStream, " end readonly def\n", 19);
626 // write the guts of the dictionary
627 cvtSfnts(outputFunc, outputStream, NULL, needVerticalMetrics);
629 // end the dictionary and define the font
630 (*outputFunc)(outputStream,
631 "CIDFontName currentdict end /CIDFont defineresource pop\n",
632 56);
635 void FoFiTrueType::convertToCIDType0(char *psName,
636 FoFiOutputFunc outputFunc,
637 void *outputStream) {
638 FoFiType1C *ff;
639 int i;
641 if (!openTypeCFF) {
642 return;
644 i = seekTable("CFF ");
645 if (!checkRegion(tables[i].offset, tables[i].len)) {
646 return;
648 if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
649 tables[i].len))) {
650 return;
652 ff->convertToCIDType0(psName, outputFunc, outputStream);
653 delete ff;
656 void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
657 GBool needVerticalMetrics,
658 FoFiOutputFunc outputFunc,
659 void *outputStream) {
660 GString *buf;
661 GString *sfntsName;
662 int n, i, j;
664 if (openTypeCFF) {
665 return;
668 // write the Type 42 sfnts array
669 sfntsName = (new GString(psName))->append("_sfnts");
670 cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
671 delete sfntsName;
673 // write the descendant Type 42 fonts
674 n = cidMap ? nCIDs : nGlyphs;
675 for (i = 0; i < n; i += 256) {
676 (*outputFunc)(outputStream, "10 dict begin\n", 14);
677 (*outputFunc)(outputStream, "/FontName /", 11);
678 (*outputFunc)(outputStream, psName, strlen(psName));
679 buf = GString::format("_{0:02x} def\n", i >> 8);
680 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
681 delete buf;
682 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
683 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
684 buf = GString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
685 bbox[0], bbox[1], bbox[2], bbox[3]);
686 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
687 delete buf;
688 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
689 (*outputFunc)(outputStream, "/sfnts ", 7);
690 (*outputFunc)(outputStream, psName, strlen(psName));
691 (*outputFunc)(outputStream, "_sfnts def\n", 11);
692 (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
693 for (j = 0; j < 256 && i+j < n; ++j) {
694 buf = GString::format("dup {0:d} /c{1:02x} put\n", j, j);
695 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
696 delete buf;
698 (*outputFunc)(outputStream, "readonly def\n", 13);
699 (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
700 (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
701 for (j = 0; j < 256 && i+j < n; ++j) {
702 buf = GString::format("/c{0:02x} {1:d} def\n",
703 j, cidMap ? cidMap[i+j] : i+j);
704 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
705 delete buf;
707 (*outputFunc)(outputStream, "end readonly def\n", 17);
708 (*outputFunc)(outputStream,
709 "FontName currentdict end definefont pop\n", 40);
712 // write the Type 0 parent font
713 (*outputFunc)(outputStream, "16 dict begin\n", 14);
714 (*outputFunc)(outputStream, "/FontName /", 11);
715 (*outputFunc)(outputStream, psName, strlen(psName));
716 (*outputFunc)(outputStream, " def\n", 5);
717 (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
718 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
719 (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
720 (*outputFunc)(outputStream, "/Encoding [\n", 12);
721 for (i = 0; i < n; i += 256) {
722 buf = GString::format("{0:d}\n", i >> 8);
723 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
724 delete buf;
726 (*outputFunc)(outputStream, "] def\n", 6);
727 (*outputFunc)(outputStream, "/FDepVector [\n", 14);
728 for (i = 0; i < n; i += 256) {
729 (*outputFunc)(outputStream, "/", 1);
730 (*outputFunc)(outputStream, psName, strlen(psName));
731 buf = GString::format("_{0:02x} findfont\n", i >> 8);
732 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
733 delete buf;
735 (*outputFunc)(outputStream, "] def\n", 6);
736 (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
739 void FoFiTrueType::convertToType0(char *psName,
740 FoFiOutputFunc outputFunc,
741 void *outputStream) {
742 FoFiType1C *ff;
743 int i;
745 if (!openTypeCFF) {
746 return;
748 i = seekTable("CFF ");
749 if (!checkRegion(tables[i].offset, tables[i].len)) {
750 return;
752 if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
753 tables[i].len))) {
754 return;
756 ff->convertToType0(psName, outputFunc, outputStream);
757 delete ff;
760 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
761 void *outputStream, char *name,
762 Gushort *codeToGID) {
763 // this substitute cmap table maps char codes 0000-ffff directly to
764 // glyphs 0000-ffff
765 static char cmapTab[36] = {
766 0, 0, // table version number
767 0, 1, // number of encoding tables
768 0, 1, // platform ID
769 0, 0, // encoding ID
770 0, 0, 0, 12, // offset of subtable
771 0, 4, // subtable format
772 0, 24, // subtable length
773 0, 0, // subtable version
774 0, 2, // segment count * 2
775 0, 2, // 2 * 2 ^ floor(log2(segCount))
776 0, 0, // floor(log2(segCount))
777 0, 0, // 2*segCount - 2*2^floor(log2(segCount))
778 (char)0xff, (char)0xff, // endCount[0]
779 0, 0, // reserved
780 0, 0, // startCount[0]
781 0, 0, // idDelta[0]
782 0, 0 // pad to a mulitple of four bytes
784 static char nameTab[8] = {
785 0, 0, // format
786 0, 0, // number of name records
787 0, 6, // offset to start of string storage
788 0, 0 // pad to multiple of four bytes
790 static char postTab[32] = {
791 0, 1, 0, 0, // format
792 0, 0, 0, 0, // italic angle
793 0, 0, // underline position
794 0, 0, // underline thickness
795 0, 0, 0, 0, // fixed pitch
796 0, 0, 0, 0, // min Type 42 memory
797 0, 0, 0, 0, // max Type 42 memory
798 0, 0, 0, 0, // min Type 1 memory
799 0, 0, 0, 0 // max Type 1 memory
801 static char os2Tab[86] = {
802 0, 1, // version
803 0, 1, // xAvgCharWidth
804 0, 0, // usWeightClass
805 0, 0, // usWidthClass
806 0, 0, // fsType
807 0, 0, // ySubscriptXSize
808 0, 0, // ySubscriptYSize
809 0, 0, // ySubscriptXOffset
810 0, 0, // ySubscriptYOffset
811 0, 0, // ySuperscriptXSize
812 0, 0, // ySuperscriptYSize
813 0, 0, // ySuperscriptXOffset
814 0, 0, // ySuperscriptYOffset
815 0, 0, // yStrikeoutSize
816 0, 0, // yStrikeoutPosition
817 0, 0, // sFamilyClass
818 0, 0, 0, 0, 0, // panose
819 0, 0, 0, 0, 0,
820 0, 0, 0, 0, // ulUnicodeRange1
821 0, 0, 0, 0, // ulUnicodeRange2
822 0, 0, 0, 0, // ulUnicodeRange3
823 0, 0, 0, 0, // ulUnicodeRange4
824 0, 0, 0, 0, // achVendID
825 0, 0, // fsSelection
826 0, 0, // usFirstCharIndex
827 0, 0, // usLastCharIndex
828 0, 0, // sTypoAscender
829 0, 0, // sTypoDescender
830 0, 0, // sTypoLineGap
831 0, 0, // usWinAscent
832 0, 0, // usWinDescent
833 0, 0, 0, 0, // ulCodePageRange1
834 0, 0, 0, 0 // ulCodePageRange2
836 GBool missingCmap, missingName, missingPost, missingOS2;
837 GBool unsortedLoca, badCmapLen, abbrevHMTX;
838 int nZeroLengthTables;
839 int nHMetrics, advWidth, lsb;
840 TrueTypeLoca *locaTable;
841 TrueTypeTable *newTables;
842 char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab;
843 int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
844 int newHHEALen, newHMTXLen;
845 Guint locaChecksum, glyfChecksum, fileChecksum;
846 char *tableDir;
847 char locaBuf[4], checksumBuf[4];
848 GBool ok;
849 Guint t;
850 int pos, i, j, k, n;
852 if (openTypeCFF) {
853 return;
856 // check for missing tables
857 // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver
858 // will embed a PCL TrueType font with the pitch field set to zero,
859 // which apparently causes divide-by-zero errors. As far as I can
860 // tell, the only important field in the OS/2 table is
861 // xAvgCharWidth.)
862 missingCmap = (cmapIdx = seekTable("cmap")) < 0;
863 missingName = seekTable("name") < 0;
864 missingPost = seekTable("post") < 0;
865 missingOS2 = seekTable("OS/2") < 0;
867 // read the loca table, check to see if it's sorted
868 locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
869 unsortedLoca = gFalse;
870 i = seekTable("loca");
871 pos = tables[i].offset;
872 ok = gTrue;
873 for (i = 0; i <= nGlyphs; ++i) {
874 if (locaFmt) {
875 locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
876 } else {
877 locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
879 if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
880 unsortedLoca = gTrue;
882 // glyph descriptions must be at least 12 bytes long (nContours,
883 // xMin, yMin, xMax, yMax, instructionLength - two bytes each);
884 // invalid glyph descriptions (even if they're never used) make
885 // Windows choke, so we work around that problem here (ideally,
886 // this would parse the glyph descriptions in the glyf table and
887 // remove any that were invalid, but this quick test is a decent
888 // start)
889 if (i > 0 &&
890 locaTable[i].origOffset - locaTable[i-1].origOffset > 0 &&
891 locaTable[i].origOffset - locaTable[i-1].origOffset < 12) {
892 locaTable[i-1].origOffset = locaTable[i].origOffset;
893 unsortedLoca = gTrue;
895 locaTable[i].idx = i;
898 // check for zero-length tables
899 nZeroLengthTables = 0;
900 for (i = 0; i < nTables; ++i) {
901 if (tables[i].len == 0) {
902 ++nZeroLengthTables;
906 // check for an incorrect cmap table length
907 badCmapLen = gFalse;
908 cmapLen = 0; // make gcc happy
909 if (!missingCmap) {
910 cmapLen = cmaps[0].offset + cmaps[0].len;
911 for (i = 1; i < nCmaps; ++i) {
912 if (cmaps[i].offset + cmaps[i].len > cmapLen) {
913 cmapLen = cmaps[i].offset + cmaps[i].len;
916 cmapLen -= tables[cmapIdx].offset;
917 if (cmapLen > tables[cmapIdx].len) {
918 badCmapLen = gTrue;
922 // check for an abbreviated hmtx table (this is completely legal,
923 // but confuses the Microsoft PCL5 printer driver, which generates
924 // embedded fonts with the pitch field set to zero)
925 i = seekTable("hhea");
926 nHMetrics = getU16BE(tables[i].offset + 34, &ok);
927 abbrevHMTX = nHMetrics < nGlyphs;
929 // if nothing is broken, just write the TTF file as is
930 if (!missingCmap && !missingName && !missingPost && !missingOS2 &&
931 !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 &&
932 !name && !codeToGID) {
933 (*outputFunc)(outputStream, (char *)file, len);
934 goto done1;
937 // sort the 'loca' table: some (non-compliant) fonts have
938 // out-of-order loca tables; in order to correctly handle the case
939 // where (compliant) fonts have empty entries in the middle of the
940 // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
941 // and idx as its secondary key (ensuring that adjacent entries with
942 // the same pos value remain in the same order)
943 glyfLen = 0; // make gcc happy
944 if (unsortedLoca) {
945 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
946 &cmpTrueTypeLocaOffset);
947 for (i = 0; i < nGlyphs; ++i) {
948 locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
950 locaTable[nGlyphs].len = 0;
951 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
952 &cmpTrueTypeLocaIdx);
953 pos = 0;
954 for (i = 0; i <= nGlyphs; ++i) {
955 locaTable[i].newOffset = pos;
956 pos += locaTable[i].len;
957 if (pos & 3) {
958 pos += 4 - (pos & 3);
961 glyfLen = pos;
964 // compute checksums for the loca and glyf tables
965 locaChecksum = glyfChecksum = 0;
966 if (unsortedLoca) {
967 if (locaFmt) {
968 for (j = 0; j <= nGlyphs; ++j) {
969 locaChecksum += locaTable[j].newOffset;
971 } else {
972 for (j = 0; j <= nGlyphs; j += 2) {
973 locaChecksum += locaTable[j].newOffset << 16;
974 if (j + 1 <= nGlyphs) {
975 locaChecksum += locaTable[j+1].newOffset;
979 pos = tables[seekTable("glyf")].offset;
980 for (j = 0; j < nGlyphs; ++j) {
981 n = locaTable[j].len;
982 if (n > 0) {
983 k = locaTable[j].origOffset;
984 if (checkRegion(pos + k, n)) {
985 glyfChecksum += computeTableChecksum(file + pos + k, n);
991 // construct the new name table
992 if (name) {
993 n = strlen(name);
994 newNameLen = (6 + 4*12 + 2 * (3*n + 7) + 3) & ~3;
995 newNameTab = (char *)gmalloc(newNameLen);
996 memset(newNameTab, 0, newNameLen);
997 newNameTab[0] = 0; // format selector
998 newNameTab[1] = 0;
999 newNameTab[2] = 0; // number of name records
1000 newNameTab[3] = 4;
1001 newNameTab[4] = 0; // offset to start of string storage
1002 newNameTab[5] = 6 + 4*12;
1003 next = 0;
1004 for (i = 0; i < 4; ++i) {
1005 newNameTab[6 + i*12 + 0] = 0; // platform ID = Microsoft
1006 newNameTab[6 + i*12 + 1] = 3;
1007 newNameTab[6 + i*12 + 2] = 0; // encoding ID = Unicode
1008 newNameTab[6 + i*12 + 3] = 1;
1009 newNameTab[6 + i*12 + 4] = 0x04; // language ID = American English
1010 newNameTab[6 + i*12 + 5] = 0x09;
1011 newNameTab[6 + i*12 + 6] = 0; // name ID
1012 newNameTab[6 + i*12 + 7] = i + 1;
1013 newNameTab[6 + i*12 + 8] = i+1 == 2 ? 0 : ((2*n) >> 8); // string length
1014 newNameTab[6 + i*12 + 9] = i+1 == 2 ? 14 : ((2*n) & 0xff);
1015 newNameTab[6 + i*12 + 10] = next >> 8; // string offset
1016 newNameTab[6 + i*12 + 11] = next & 0xff;
1017 if (i+1 == 2) {
1018 memcpy(newNameTab + 6 + 4*12 + next, "\0R\0e\0g\0u\0l\0a\0r", 14);
1019 next += 14;
1020 } else {
1021 for (j = 0; j < n; ++j) {
1022 newNameTab[6 + 4*12 + next + 2*j] = 0;
1023 newNameTab[6 + 4*12 + next + 2*j + 1] = name[j];
1025 next += 2*n;
1028 } else {
1029 newNameLen = 0;
1030 newNameTab = NULL;
1033 // construct the new cmap table
1034 if (codeToGID) {
1035 newCmapLen = 44 + 256 * 2;
1036 newCmapTab = (char *)gmalloc(newCmapLen);
1037 newCmapTab[0] = 0; // table version number = 0
1038 newCmapTab[1] = 0;
1039 newCmapTab[2] = 0; // number of encoding tables = 1
1040 newCmapTab[3] = 1;
1041 newCmapTab[4] = 0; // platform ID = Microsoft
1042 newCmapTab[5] = 3;
1043 newCmapTab[6] = 0; // encoding ID = Unicode
1044 newCmapTab[7] = 1;
1045 newCmapTab[8] = 0; // offset of subtable
1046 newCmapTab[9] = 0;
1047 newCmapTab[10] = 0;
1048 newCmapTab[11] = 12;
1049 newCmapTab[12] = 0; // subtable format = 4
1050 newCmapTab[13] = 4;
1051 newCmapTab[14] = 0x02; // subtable length
1052 newCmapTab[15] = 0x20;
1053 newCmapTab[16] = 0; // subtable version = 0
1054 newCmapTab[17] = 0;
1055 newCmapTab[18] = 0; // segment count * 2
1056 newCmapTab[19] = 4;
1057 newCmapTab[20] = 0; // 2 * 2 ^ floor(log2(segCount))
1058 newCmapTab[21] = 4;
1059 newCmapTab[22] = 0; // floor(log2(segCount))
1060 newCmapTab[23] = 1;
1061 newCmapTab[24] = 0; // 2*segCount - 2*2^floor(log2(segCount))
1062 newCmapTab[25] = 0;
1063 newCmapTab[26] = 0x00; // endCount[0]
1064 newCmapTab[27] = (char)0xff;
1065 newCmapTab[28] = (char)0xff; // endCount[1]
1066 newCmapTab[29] = (char)0xff;
1067 newCmapTab[30] = 0; // reserved
1068 newCmapTab[31] = 0;
1069 newCmapTab[32] = 0x00; // startCount[0]
1070 newCmapTab[33] = 0x00;
1071 newCmapTab[34] = (char)0xff; // startCount[1]
1072 newCmapTab[35] = (char)0xff;
1073 newCmapTab[36] = 0; // idDelta[0]
1074 newCmapTab[37] = 0;
1075 newCmapTab[38] = 0; // idDelta[1]
1076 newCmapTab[39] = 1;
1077 newCmapTab[40] = 0; // idRangeOffset[0]
1078 newCmapTab[41] = 4;
1079 newCmapTab[42] = 0; // idRangeOffset[1]
1080 newCmapTab[43] = 0;
1081 for (i = 0; i < 256; ++i) {
1082 newCmapTab[44 + 2*i] = codeToGID[i] >> 8;
1083 newCmapTab[44 + 2*i + 1] = codeToGID[i] & 0xff;
1085 } else {
1086 newCmapLen = 0;
1087 newCmapTab = NULL;
1090 // generate the new hmtx table and the updated hhea table
1091 if (abbrevHMTX) {
1092 i = seekTable("hhea");
1093 pos = tables[i].offset;
1094 newHHEALen = 36;
1095 newHHEATab = (char *)gmalloc(newHHEALen);
1096 for (i = 0; i < newHHEALen; ++i) {
1097 newHHEATab[i] = getU8(pos++, &ok);
1099 newHHEATab[34] = nGlyphs >> 8;
1100 newHHEATab[35] = nGlyphs & 0xff;
1101 i = seekTable("hmtx");
1102 pos = tables[i].offset;
1103 newHMTXLen = 4 * nGlyphs;
1104 newHMTXTab = (char *)gmalloc(newHMTXLen);
1105 advWidth = 0;
1106 for (i = 0; i < nHMetrics; ++i) {
1107 advWidth = getU16BE(pos, &ok);
1108 lsb = getU16BE(pos + 2, &ok);
1109 pos += 4;
1110 newHMTXTab[4*i ] = advWidth >> 8;
1111 newHMTXTab[4*i + 1] = advWidth & 0xff;
1112 newHMTXTab[4*i + 2] = lsb >> 8;
1113 newHMTXTab[4*i + 3] = lsb & 0xff;
1115 for (; i < nGlyphs; ++i) {
1116 lsb = getU16BE(pos, &ok);
1117 pos += 2;
1118 newHMTXTab[4*i ] = advWidth >> 8;
1119 newHMTXTab[4*i + 1] = advWidth & 0xff;
1120 newHMTXTab[4*i + 2] = lsb >> 8;
1121 newHMTXTab[4*i + 3] = lsb & 0xff;
1123 } else {
1124 newHHEATab = newHMTXTab = NULL;
1125 newHHEALen = newHMTXLen = 0; // make gcc happy
1128 // construct the new table directory:
1129 // - keep all original tables with non-zero length
1130 // - fix the cmap table's length, if necessary
1131 // - add missing tables
1132 // - sort the table by tag
1133 // - compute new table positions, including 4-byte alignment
1134 // - (re)compute table checksums
1135 nNewTables = nTables - nZeroLengthTables +
1136 (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
1137 (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0);
1138 newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
1139 j = 0;
1140 for (i = 0; i < nTables; ++i) {
1141 if (tables[i].len > 0) {
1142 newTables[j] = tables[i];
1143 newTables[j].origOffset = tables[i].offset;
1144 if (checkRegion(tables[i].offset, newTables[i].len)) {
1145 newTables[j].checksum =
1146 computeTableChecksum(file + tables[i].offset, tables[i].len);
1147 if (tables[i].tag == headTag) {
1148 // don't include the file checksum
1149 newTables[j].checksum -= getU32BE(tables[i].offset + 8, &ok);
1152 if (newTables[j].tag == cmapTag && codeToGID) {
1153 newTables[j].len = newCmapLen;
1154 newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
1155 newCmapLen);
1156 } else if (newTables[j].tag == cmapTag && badCmapLen) {
1157 newTables[j].len = cmapLen;
1158 } else if (newTables[j].tag == locaTag && unsortedLoca) {
1159 newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1160 newTables[j].checksum = locaChecksum;
1161 } else if (newTables[j].tag == glyfTag && unsortedLoca) {
1162 newTables[j].len = glyfLen;
1163 newTables[j].checksum = glyfChecksum;
1164 } else if (newTables[j].tag == nameTag && name) {
1165 newTables[j].len = newNameLen;
1166 newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
1167 newNameLen);
1168 } else if (newTables[j].tag == hheaTag && abbrevHMTX) {
1169 newTables[j].len = newHHEALen;
1170 newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab,
1171 newHHEALen);
1172 } else if (newTables[j].tag == hmtxTag && abbrevHMTX) {
1173 newTables[j].len = newHMTXLen;
1174 newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab,
1175 newHMTXLen);
1177 ++j;
1180 if (missingCmap) {
1181 newTables[j].tag = cmapTag;
1182 if (codeToGID) {
1183 newTables[j].checksum = computeTableChecksum((Guchar *)newCmapTab,
1184 newCmapLen);
1185 newTables[j].len = newCmapLen;
1186 } else {
1187 newTables[j].checksum = computeTableChecksum((Guchar *)cmapTab,
1188 sizeof(cmapTab));
1189 newTables[j].len = sizeof(cmapTab);
1191 ++j;
1193 if (missingName) {
1194 newTables[j].tag = nameTag;
1195 if (name) {
1196 newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
1197 newNameLen);
1198 newTables[j].len = newNameLen;
1199 } else {
1200 newTables[j].checksum = computeTableChecksum((Guchar *)nameTab,
1201 sizeof(nameTab));
1202 newTables[j].len = sizeof(nameTab);
1204 ++j;
1206 if (missingPost) {
1207 newTables[j].tag = postTag;
1208 newTables[j].checksum = computeTableChecksum((Guchar *)postTab,
1209 sizeof(postTab));
1210 newTables[j].len = sizeof(postTab);
1211 ++j;
1213 if (missingOS2) {
1214 newTables[j].tag = os2Tag;
1215 newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab,
1216 sizeof(os2Tab));
1217 newTables[j].len = sizeof(os2Tab);
1218 ++j;
1220 qsort(newTables, nNewTables, sizeof(TrueTypeTable),
1221 &cmpTrueTypeTableTag);
1222 pos = 12 + nNewTables * 16;
1223 for (i = 0; i < nNewTables; ++i) {
1224 newTables[i].offset = pos;
1225 pos += newTables[i].len;
1226 if (pos & 3) {
1227 pos += 4 - (pos & 3);
1231 // write the table directory
1232 tableDir = (char *)gmalloc(12 + nNewTables * 16);
1233 tableDir[0] = 0x00; // sfnt version
1234 tableDir[1] = 0x01;
1235 tableDir[2] = 0x00;
1236 tableDir[3] = 0x00;
1237 tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables
1238 tableDir[5] = (char)(nNewTables & 0xff);
1239 for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
1240 t = 1 << (4 + i);
1241 tableDir[6] = (char)((t >> 8) & 0xff); // searchRange
1242 tableDir[7] = (char)(t & 0xff);
1243 tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector
1244 tableDir[9] = (char)(i & 0xff);
1245 t = nNewTables * 16 - t;
1246 tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift
1247 tableDir[11] = (char)(t & 0xff);
1248 pos = 12;
1249 for (i = 0; i < nNewTables; ++i) {
1250 tableDir[pos ] = (char)(newTables[i].tag >> 24);
1251 tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
1252 tableDir[pos+ 2] = (char)(newTables[i].tag >> 8);
1253 tableDir[pos+ 3] = (char) newTables[i].tag;
1254 tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
1255 tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
1256 tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8);
1257 tableDir[pos+ 7] = (char) newTables[i].checksum;
1258 tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
1259 tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
1260 tableDir[pos+10] = (char)(newTables[i].offset >> 8);
1261 tableDir[pos+11] = (char) newTables[i].offset;
1262 tableDir[pos+12] = (char)(newTables[i].len >> 24);
1263 tableDir[pos+13] = (char)(newTables[i].len >> 16);
1264 tableDir[pos+14] = (char)(newTables[i].len >> 8);
1265 tableDir[pos+15] = (char) newTables[i].len;
1266 pos += 16;
1268 (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
1270 // compute the file checksum
1271 fileChecksum = computeTableChecksum((Guchar *)tableDir,
1272 12 + nNewTables * 16);
1273 for (i = 0; i < nNewTables; ++i) {
1274 fileChecksum += newTables[i].checksum;
1276 fileChecksum = 0xb1b0afba - fileChecksum;
1278 // write the tables
1279 for (i = 0; i < nNewTables; ++i) {
1280 if (newTables[i].tag == headTag) {
1281 if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1282 (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset, 8);
1283 checksumBuf[0] = fileChecksum >> 24;
1284 checksumBuf[1] = fileChecksum >> 16;
1285 checksumBuf[2] = fileChecksum >> 8;
1286 checksumBuf[3] = fileChecksum;
1287 (*outputFunc)(outputStream, checksumBuf, 4);
1288 (*outputFunc)(outputStream,
1289 (char *)file + newTables[i].origOffset + 12,
1290 newTables[i].len - 12);
1291 } else {
1292 for (j = 0; j < newTables[i].len; ++j) {
1293 (*outputFunc)(outputStream, "\0", 1);
1296 } else if (newTables[i].tag == cmapTag && codeToGID) {
1297 (*outputFunc)(outputStream, newCmapTab, newTables[i].len);
1298 } else if (newTables[i].tag == cmapTag && missingCmap) {
1299 (*outputFunc)(outputStream, cmapTab, newTables[i].len);
1300 } else if (newTables[i].tag == nameTag && name) {
1301 (*outputFunc)(outputStream, newNameTab, newTables[i].len);
1302 } else if (newTables[i].tag == nameTag && missingName) {
1303 (*outputFunc)(outputStream, nameTab, newTables[i].len);
1304 } else if (newTables[i].tag == postTag && missingPost) {
1305 (*outputFunc)(outputStream, postTab, newTables[i].len);
1306 } else if (newTables[i].tag == os2Tag && missingOS2) {
1307 (*outputFunc)(outputStream, os2Tab, newTables[i].len);
1308 } else if (newTables[i].tag == hheaTag && abbrevHMTX) {
1309 (*outputFunc)(outputStream, newHHEATab, newTables[i].len);
1310 } else if (newTables[i].tag == hmtxTag && abbrevHMTX) {
1311 (*outputFunc)(outputStream, newHMTXTab, newTables[i].len);
1312 } else if (newTables[i].tag == locaTag && unsortedLoca) {
1313 for (j = 0; j <= nGlyphs; ++j) {
1314 if (locaFmt) {
1315 locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
1316 locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
1317 locaBuf[2] = (char)(locaTable[j].newOffset >> 8);
1318 locaBuf[3] = (char) locaTable[j].newOffset;
1319 (*outputFunc)(outputStream, locaBuf, 4);
1320 } else {
1321 locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
1322 locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
1323 (*outputFunc)(outputStream, locaBuf, 2);
1326 } else if (newTables[i].tag == glyfTag && unsortedLoca) {
1327 pos = tables[seekTable("glyf")].offset;
1328 for (j = 0; j < nGlyphs; ++j) {
1329 n = locaTable[j].len;
1330 if (n > 0) {
1331 k = locaTable[j].origOffset;
1332 if (checkRegion(pos + k, n)) {
1333 (*outputFunc)(outputStream, (char *)file + pos + k, n);
1334 } else {
1335 for (k = 0; k < n; ++k) {
1336 (*outputFunc)(outputStream, "\0", 1);
1339 if ((k = locaTable[j].len & 3)) {
1340 (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
1344 } else {
1345 if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
1346 (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
1347 newTables[i].len);
1348 } else {
1349 for (j = 0; j < newTables[i].len; ++j) {
1350 (*outputFunc)(outputStream, "\0", 1);
1354 if (newTables[i].len & 3) {
1355 (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
1359 gfree(newHMTXTab);
1360 gfree(newHHEATab);
1361 gfree(newCmapTab);
1362 gfree(newNameTab);
1363 gfree(tableDir);
1364 gfree(newTables);
1365 done1:
1366 gfree(locaTable);
1369 void FoFiTrueType::cvtEncoding(char **encoding,
1370 FoFiOutputFunc outputFunc,
1371 void *outputStream) {
1372 char *name;
1373 GString *buf;
1374 int i;
1376 (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
1377 if (encoding) {
1378 for (i = 0; i < 256; ++i) {
1379 if (!(name = encoding[i])) {
1380 name = ".notdef";
1382 buf = GString::format("dup {0:d} /", i);
1383 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1384 delete buf;
1385 (*outputFunc)(outputStream, name, strlen(name));
1386 (*outputFunc)(outputStream, " put\n", 5);
1388 } else {
1389 for (i = 0; i < 256; ++i) {
1390 buf = GString::format("dup {0:d} /c{1:02x} put\n", i, i);
1391 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1392 delete buf;
1395 (*outputFunc)(outputStream, "readonly def\n", 13);
1398 void FoFiTrueType::cvtCharStrings(char **encoding,
1399 Gushort *codeToGID,
1400 FoFiOutputFunc outputFunc,
1401 void *outputStream) {
1402 char *name;
1403 GString *buf;
1404 char buf2[16];
1405 int i, k;
1407 // always define '.notdef'
1408 (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
1409 (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
1411 // if there's no 'cmap' table, punt
1412 if (nCmaps == 0) {
1413 goto err;
1416 // map char name to glyph index:
1417 // 1. use encoding to map name to char code
1418 // 2. use codeToGID to map char code to glyph index
1419 // N.B. We do this in reverse order because font subsets can have
1420 // weird encodings that use the same character name twice, and
1421 // the first definition is probably the one we want.
1422 k = 0; // make gcc happy
1423 for (i = 255; i >= 0; --i) {
1424 if (encoding) {
1425 name = encoding[i];
1426 } else {
1427 sprintf(buf2, "c%02x", i);
1428 name = buf2;
1430 if (name && strcmp(name, ".notdef")) {
1431 k = codeToGID[i];
1432 // note: Distiller (maybe Adobe's PS interpreter in general)
1433 // doesn't like TrueType fonts that have CharStrings entries
1434 // which point to nonexistent glyphs, hence the (k < nGlyphs)
1435 // test
1436 if (k > 0 && k < nGlyphs) {
1437 (*outputFunc)(outputStream, "/", 1);
1438 (*outputFunc)(outputStream, name, strlen(name));
1439 buf = GString::format(" {0:d} def\n", k);
1440 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1441 delete buf;
1446 err:
1447 (*outputFunc)(outputStream, "end readonly def\n", 17);
1450 void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
1451 void *outputStream, GString *name,
1452 GBool needVerticalMetrics) {
1453 Guchar headData[54];
1454 TrueTypeLoca *locaTable;
1455 Guchar *locaData;
1456 TrueTypeTable newTables[nT42Tables];
1457 Guchar tableDir[12 + nT42Tables*16];
1458 GBool ok;
1459 Guint checksum;
1460 int nNewTables;
1461 int length, pos, glyfPos, i, j, k;
1462 Guchar vheaTab[36] = {
1463 0, 1, 0, 0, // table version number
1464 0, 0, // ascent
1465 0, 0, // descent
1466 0, 0, // reserved
1467 0, 0, // max advance height
1468 0, 0, // min top side bearing
1469 0, 0, // min bottom side bearing
1470 0, 0, // y max extent
1471 0, 0, // caret slope rise
1472 0, 1, // caret slope run
1473 0, 0, // caret offset
1474 0, 0, // reserved
1475 0, 0, // reserved
1476 0, 0, // reserved
1477 0, 0, // reserved
1478 0, 0, // metric data format
1479 0, 1 // number of advance heights in vmtx table
1481 Guchar *vmtxTab;
1482 GBool needVhea, needVmtx;
1483 int advance;
1485 // construct the 'head' table, zero out the font checksum
1486 i = seekTable("head");
1487 pos = tables[i].offset;
1488 if (!checkRegion(pos, 54)) {
1489 return;
1491 memcpy(headData, file + pos, 54);
1492 headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
1494 // read the original 'loca' table, pad entries out to 4 bytes, and
1495 // sort it into proper order -- some (non-compliant) fonts have
1496 // out-of-order loca tables; in order to correctly handle the case
1497 // where (compliant) fonts have empty entries in the middle of the
1498 // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
1499 // and idx as its secondary key (ensuring that adjacent entries with
1500 // the same pos value remain in the same order)
1501 locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
1502 i = seekTable("loca");
1503 pos = tables[i].offset;
1504 ok = gTrue;
1505 for (i = 0; i <= nGlyphs; ++i) {
1506 locaTable[i].idx = i;
1507 if (locaFmt) {
1508 locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
1509 } else {
1510 locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
1513 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1514 &cmpTrueTypeLocaOffset);
1515 for (i = 0; i < nGlyphs; ++i) {
1516 locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
1518 locaTable[nGlyphs].len = 0;
1519 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1520 &cmpTrueTypeLocaIdx);
1521 pos = 0;
1522 for (i = 0; i <= nGlyphs; ++i) {
1523 locaTable[i].newOffset = pos;
1524 pos += locaTable[i].len;
1525 if (pos & 3) {
1526 pos += 4 - (pos & 3);
1530 // construct the new 'loca' table
1531 locaData = (Guchar *)gmallocn(nGlyphs + 1, (locaFmt ? 4 : 2));
1532 for (i = 0; i <= nGlyphs; ++i) {
1533 pos = locaTable[i].newOffset;
1534 if (locaFmt) {
1535 locaData[4*i ] = (Guchar)(pos >> 24);
1536 locaData[4*i+1] = (Guchar)(pos >> 16);
1537 locaData[4*i+2] = (Guchar)(pos >> 8);
1538 locaData[4*i+3] = (Guchar) pos;
1539 } else {
1540 locaData[2*i ] = (Guchar)(pos >> 9);
1541 locaData[2*i+1] = (Guchar)(pos >> 1);
1545 // count the number of tables
1546 nNewTables = 0;
1547 for (i = 0; i < nT42Tables; ++i) {
1548 if (t42Tables[i].required ||
1549 seekTable(t42Tables[i].tag) >= 0) {
1550 ++nNewTables;
1553 vmtxTab = NULL; // make gcc happy
1554 advance = 0; // make gcc happy
1555 if (needVerticalMetrics) {
1556 needVhea = seekTable("vhea") < 0;
1557 needVmtx = seekTable("vmtx") < 0;
1558 if (needVhea || needVmtx) {
1559 i = seekTable("head");
1560 advance = getU16BE(tables[i].offset + 18, &ok); // units per em
1561 if (needVhea) {
1562 ++nNewTables;
1564 if (needVmtx) {
1565 ++nNewTables;
1570 // construct the new table headers, including table checksums
1571 // (pad each table out to a multiple of 4 bytes)
1572 pos = 12 + nNewTables*16;
1573 k = 0;
1574 for (i = 0; i < nT42Tables; ++i) {
1575 length = -1;
1576 checksum = 0; // make gcc happy
1577 if (i == t42HeadTable) {
1578 length = 54;
1579 checksum = computeTableChecksum(headData, 54);
1580 } else if (i == t42LocaTable) {
1581 length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1582 checksum = computeTableChecksum(locaData, length);
1583 } else if (i == t42GlyfTable) {
1584 length = 0;
1585 checksum = 0;
1586 glyfPos = tables[seekTable("glyf")].offset;
1587 for (j = 0; j < nGlyphs; ++j) {
1588 length += locaTable[j].len;
1589 if (length & 3) {
1590 length += 4 - (length & 3);
1592 if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1593 checksum +=
1594 computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
1595 locaTable[j].len);
1598 } else {
1599 if ((j = seekTable(t42Tables[i].tag)) >= 0) {
1600 length = tables[j].len;
1601 if (checkRegion(tables[j].offset, length)) {
1602 checksum = computeTableChecksum(file + tables[j].offset, length);
1604 } else if (needVerticalMetrics && i == t42VheaTable) {
1605 vheaTab[10] = advance / 256; // max advance height
1606 vheaTab[11] = advance % 256;
1607 length = sizeof(vheaTab);
1608 checksum = computeTableChecksum(vheaTab, length);
1609 } else if (needVerticalMetrics && i == t42VmtxTable) {
1610 length = 4 + (nGlyphs - 1) * 4;
1611 vmtxTab = (Guchar *)gmalloc(length);
1612 vmtxTab[0] = advance / 256;
1613 vmtxTab[1] = advance % 256;
1614 for (j = 2; j < length; j += 2) {
1615 vmtxTab[j] = 0;
1616 vmtxTab[j+1] = 0;
1618 checksum = computeTableChecksum(vmtxTab, length);
1619 } else if (t42Tables[i].required) {
1620 //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1621 //~ t42Tables[i].tag);
1622 length = 0;
1623 checksum = 0;
1626 if (length >= 0) {
1627 newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
1628 ((t42Tables[i].tag[1] & 0xff) << 16) |
1629 ((t42Tables[i].tag[2] & 0xff) << 8) |
1630 (t42Tables[i].tag[3] & 0xff);
1631 newTables[k].checksum = checksum;
1632 newTables[k].offset = pos;
1633 newTables[k].len = length;
1634 pos += length;
1635 if (pos & 3) {
1636 pos += 4 - (length & 3);
1638 ++k;
1642 // construct the table directory
1643 tableDir[0] = 0x00; // sfnt version
1644 tableDir[1] = 0x01;
1645 tableDir[2] = 0x00;
1646 tableDir[3] = 0x00;
1647 tableDir[4] = 0; // numTables
1648 tableDir[5] = nNewTables;
1649 tableDir[6] = 0; // searchRange
1650 tableDir[7] = (Guchar)128;
1651 tableDir[8] = 0; // entrySelector
1652 tableDir[9] = 3;
1653 tableDir[10] = 0; // rangeShift
1654 tableDir[11] = (Guchar)(16 * nNewTables - 128);
1655 pos = 12;
1656 for (i = 0; i < nNewTables; ++i) {
1657 tableDir[pos ] = (Guchar)(newTables[i].tag >> 24);
1658 tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
1659 tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8);
1660 tableDir[pos+ 3] = (Guchar) newTables[i].tag;
1661 tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
1662 tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
1663 tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8);
1664 tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
1665 tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
1666 tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
1667 tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8);
1668 tableDir[pos+11] = (Guchar) newTables[i].offset;
1669 tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
1670 tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
1671 tableDir[pos+14] = (Guchar)(newTables[i].len >> 8);
1672 tableDir[pos+15] = (Guchar) newTables[i].len;
1673 pos += 16;
1676 // compute the font checksum and store it in the head table
1677 checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
1678 for (i = 0; i < nNewTables; ++i) {
1679 checksum += newTables[i].checksum;
1681 checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
1682 headData[ 8] = (Guchar)(checksum >> 24);
1683 headData[ 9] = (Guchar)(checksum >> 16);
1684 headData[10] = (Guchar)(checksum >> 8);
1685 headData[11] = (Guchar) checksum;
1687 // start the sfnts array
1688 if (name) {
1689 (*outputFunc)(outputStream, "/", 1);
1690 (*outputFunc)(outputStream, name->getCString(), name->getLength());
1691 (*outputFunc)(outputStream, " [\n", 3);
1692 } else {
1693 (*outputFunc)(outputStream, "/sfnts [\n", 9);
1696 // write the table directory
1697 dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
1699 // write the tables
1700 for (i = 0; i < nNewTables; ++i) {
1701 if (i == t42HeadTable) {
1702 dumpString(headData, 54, outputFunc, outputStream);
1703 } else if (i == t42LocaTable) {
1704 length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1705 dumpString(locaData, length, outputFunc, outputStream);
1706 } else if (i == t42GlyfTable) {
1707 glyfPos = tables[seekTable("glyf")].offset;
1708 for (j = 0; j < nGlyphs; ++j) {
1709 if (locaTable[j].len > 0 &&
1710 checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1711 dumpString(file + glyfPos + locaTable[j].origOffset,
1712 locaTable[j].len, outputFunc, outputStream);
1715 } else {
1716 // length == 0 means the table is missing and the error was
1717 // already reported during the construction of the table
1718 // headers
1719 if ((length = newTables[i].len) > 0) {
1720 if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
1721 checkRegion(tables[j].offset, tables[j].len)) {
1722 dumpString(file + tables[j].offset, tables[j].len,
1723 outputFunc, outputStream);
1724 } else if (needVerticalMetrics && i == t42VheaTable) {
1725 dumpString(vheaTab, length, outputFunc, outputStream);
1726 } else if (needVerticalMetrics && i == t42VmtxTable) {
1727 dumpString(vmtxTab, length, outputFunc, outputStream);
1728 gfree(vmtxTab);
1734 // end the sfnts array
1735 (*outputFunc)(outputStream, "] def\n", 6);
1737 gfree(locaData);
1738 gfree(locaTable);
1741 void FoFiTrueType::dumpString(Guchar *s, int length,
1742 FoFiOutputFunc outputFunc,
1743 void *outputStream) {
1744 GString *buf;
1745 int pad, i, j;
1747 (*outputFunc)(outputStream,"<", 1);
1748 for (i = 0; i < length; i += 32) {
1749 for (j = 0; j < 32 && i+j < length; ++j) {
1750 buf = GString::format("{0:02x}", s[i+j] & 0xff);
1751 (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
1752 delete buf;
1754 if (i % (65536 - 32) == 65536 - 64) {
1755 (*outputFunc)(outputStream, ">\n<", 3);
1756 } else if (i+32 < length) {
1757 (*outputFunc)(outputStream, "\n", 1);
1760 if (length & 3) {
1761 pad = 4 - (length & 3);
1762 for (i = 0; i < pad; ++i) {
1763 (*outputFunc)(outputStream, "00", 2);
1766 // add an extra zero byte because the Adobe Type 42 spec says so
1767 (*outputFunc)(outputStream, "00>\n", 4);
1770 Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
1771 Guint checksum, word;
1772 int i;
1774 checksum = 0;
1775 for (i = 0; i+3 < length; i += 4) {
1776 word = ((data[i ] & 0xff) << 24) +
1777 ((data[i+1] & 0xff) << 16) +
1778 ((data[i+2] & 0xff) << 8) +
1779 (data[i+3] & 0xff);
1780 checksum += word;
1782 if (length & 3) {
1783 word = 0;
1784 i = length & ~3;
1785 switch (length & 3) {
1786 case 3:
1787 word |= (data[i+2] & 0xff) << 8;
1788 case 2:
1789 word |= (data[i+1] & 0xff) << 16;
1790 case 1:
1791 word |= (data[i ] & 0xff) << 24;
1792 break;
1794 checksum += word;
1796 return checksum;
1799 void FoFiTrueType::parse() {
1800 Guint topTag;
1801 int pos, ver, i, j;
1803 parsedOk = gTrue;
1805 // look for a collection (TTC)
1806 topTag = getU32BE(0, &parsedOk);
1807 if (!parsedOk) {
1808 return;
1810 if (topTag == ttcfTag) {
1811 pos = getU32BE(12, &parsedOk);
1812 if (!parsedOk) {
1813 return;
1815 } else {
1816 pos = 0;
1819 // check the sfnt version
1820 ver = getU32BE(pos, &parsedOk);
1821 if (!parsedOk) {
1822 return;
1824 openTypeCFF = ver == 0x4f54544f; // 'OTTO'
1826 // read the table directory
1827 nTables = getU16BE(pos + 4, &parsedOk);
1828 if (!parsedOk) {
1829 return;
1831 tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
1832 pos += 12;
1833 for (i = 0; i < nTables; ++i) {
1834 tables[i].tag = getU32BE(pos, &parsedOk);
1835 tables[i].checksum = getU32BE(pos + 4, &parsedOk);
1836 tables[i].offset = (int)getU32BE(pos + 8, &parsedOk);
1837 tables[i].len = (int)getU32BE(pos + 12, &parsedOk);
1838 if (tables[i].offset + tables[i].len < tables[i].offset ||
1839 tables[i].offset + tables[i].len > len) {
1840 parsedOk = gFalse;
1842 pos += 16;
1844 if (!parsedOk) {
1845 return;
1848 // check for tables that are required by both the TrueType spec and
1849 // the Type 42 spec
1850 if (seekTable("head") < 0 ||
1851 seekTable("hhea") < 0 ||
1852 seekTable("maxp") < 0 ||
1853 seekTable("hmtx") < 0 ||
1854 (!openTypeCFF && seekTable("loca") < 0) ||
1855 (!openTypeCFF && seekTable("glyf") < 0) ||
1856 (openTypeCFF && seekTable("CFF ") < 0)) {
1857 parsedOk = gFalse;
1858 return;
1861 // read the cmaps
1862 if ((i = seekTable("cmap")) >= 0) {
1863 pos = tables[i].offset + 2;
1864 nCmaps = getU16BE(pos, &parsedOk);
1865 pos += 2;
1866 if (!parsedOk) {
1867 return;
1869 cmaps = (TrueTypeCmap *)gmallocn(nCmaps, sizeof(TrueTypeCmap));
1870 for (j = 0; j < nCmaps; ++j) {
1871 cmaps[j].platform = getU16BE(pos, &parsedOk);
1872 cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
1873 cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
1874 pos += 8;
1875 cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
1876 cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
1878 if (!parsedOk) {
1879 return;
1881 } else {
1882 nCmaps = 0;
1885 // get the number of glyphs from the maxp table
1886 i = seekTable("maxp");
1887 nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
1888 if (!parsedOk) {
1889 return;
1892 // get the bbox and loca table format from the head table
1893 i = seekTable("head");
1894 bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
1895 bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
1896 bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
1897 bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
1898 locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
1899 if (!parsedOk) {
1900 return;
1903 // make sure the loca table is sane (correct length and entries are
1904 // in bounds)
1905 if (!openTypeCFF) {
1906 i = seekTable("loca");
1907 if (tables[i].len < 0) {
1908 parsedOk = gFalse;
1909 return;
1911 if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
1912 nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1;
1914 for (j = 0; j <= nGlyphs; ++j) {
1915 if (locaFmt) {
1916 pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
1917 } else {
1918 pos = getU16BE(tables[i].offset + j*2, &parsedOk);
1920 if (pos < 0 || pos > len) {
1921 parsedOk = gFalse;
1924 if (!parsedOk) {
1925 return;
1929 // read the post table
1930 readPostTable();
1933 void FoFiTrueType::readPostTable() {
1934 GString *name;
1935 int tablePos, postFmt, stringIdx, stringPos;
1936 GBool ok;
1937 int i, j, n, m;
1939 ok = gTrue;
1940 if ((i = seekTable("post")) < 0) {
1941 return;
1943 tablePos = tables[i].offset;
1944 postFmt = getU32BE(tablePos, &ok);
1945 if (!ok) {
1946 goto err;
1948 if (postFmt == 0x00010000) {
1949 nameToGID = new GHash(gTrue);
1950 for (i = 0; i < 258; ++i) {
1951 nameToGID->add(new GString(macGlyphNames[i]), i);
1953 } else if (postFmt == 0x00020000) {
1954 nameToGID = new GHash(gTrue);
1955 n = getU16BE(tablePos + 32, &ok);
1956 if (!ok) {
1957 goto err;
1959 if (n > nGlyphs) {
1960 n = nGlyphs;
1962 stringIdx = 0;
1963 stringPos = tablePos + 34 + 2*n;
1964 for (i = 0; i < n; ++i) {
1965 j = getU16BE(tablePos + 34 + 2*i, &ok);
1966 if (j < 258) {
1967 nameToGID->removeInt((char *)macGlyphNames[j]);
1968 nameToGID->add(new GString(macGlyphNames[j]), i);
1969 } else {
1970 j -= 258;
1971 if (j != stringIdx) {
1972 for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
1973 stringIdx < j;
1974 ++stringIdx, stringPos += 1 + getU8(stringPos, &ok)) ;
1975 if (!ok) {
1976 goto err;
1979 m = getU8(stringPos, &ok);
1980 if (!ok || !checkRegion(stringPos + 1, m)) {
1981 goto err;
1983 name = new GString((char *)&file[stringPos + 1], m);
1984 nameToGID->removeInt(name);
1985 nameToGID->add(name, i);
1986 ++stringIdx;
1987 stringPos += 1 + m;
1990 } else if (postFmt == 0x00028000) {
1991 nameToGID = new GHash(gTrue);
1992 for (i = 0; i < nGlyphs; ++i) {
1993 j = getU8(tablePos + 32 + i, &ok);
1994 if (!ok) {
1995 goto err;
1997 if (j < 258) {
1998 nameToGID->removeInt((char *)macGlyphNames[j]);
1999 nameToGID->add(new GString(macGlyphNames[j]), i);
2004 return;
2006 err:
2007 if (nameToGID) {
2008 delete nameToGID;
2009 nameToGID = NULL;
2013 int FoFiTrueType::seekTable(char *tag) {
2014 Guint tagI;
2015 int i;
2017 tagI = ((tag[0] & 0xff) << 24) |
2018 ((tag[1] & 0xff) << 16) |
2019 ((tag[2] & 0xff) << 8) |
2020 (tag[3] & 0xff);
2021 for (i = 0; i < nTables; ++i) {
2022 if (tables[i].tag == tagI) {
2023 return i;
2026 return -1;