upgrade to xpdf 3.00.
[swftools.git] / pdf2swf / xpdf / FoFiTrueType.cc
bloba4cf43cb57e8aa640423b65f85e9161923315326
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 "gtypes.h"
17 #include "gmem.h"
18 #include "GString.h"
19 #include "GHash.h"
20 #include "FoFiTrueType.h"
23 // Terminology
24 // -----------
26 // character code = number used as an element of a text string
28 // character name = glyph name = name for a particular glyph within a
29 // font
31 // glyph index = GID = position (within some internal table in the font)
32 // where the instructions to draw a particular glyph are
33 // stored
35 // Type 1 fonts
36 // ------------
38 // Type 1 fonts contain:
40 // Encoding: array of glyph names, maps char codes to glyph names
42 // Encoding[charCode] = charName
44 // CharStrings: dictionary of instructions, keyed by character names,
45 // maps character name to glyph data
47 // CharStrings[charName] = glyphData
49 // TrueType fonts
50 // --------------
52 // TrueType fonts contain:
54 // 'cmap' table: mapping from character code to glyph index; there may
55 // be multiple cmaps in a TrueType font
57 // cmap[charCode] = gid
59 // 'post' table: mapping from glyph index to glyph name
61 // post[gid] = glyphName
63 // Type 42 fonts
64 // -------------
66 // Type 42 fonts contain:
68 // Encoding: array of glyph names, maps char codes to glyph names
70 // Encoding[charCode] = charName
72 // CharStrings: dictionary of glyph indexes, keyed by character names,
73 // maps character name to glyph index
75 // CharStrings[charName] = gid
78 //------------------------------------------------------------------------
80 struct TrueTypeTable {
81 Guint tag;
82 Guint checksum;
83 int offset;
84 int origOffset;
85 int len;
88 struct TrueTypeCmap {
89 int platform;
90 int encoding;
91 int offset;
92 int len;
93 int fmt;
96 struct TrueTypeLoca {
97 int idx;
98 int origOffset;
99 int newOffset;
100 int len;
103 #define cmapTag 0x636d6170
104 #define glyfTag 0x676c7966
105 #define locaTag 0x6c6f6361
106 #define nameTag 0x6e616d65
107 #define postTag 0x706f7374
109 static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
110 TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
111 TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
113 if (loca1->origOffset == loca2->origOffset) {
114 return loca1->idx - loca2->idx;
116 return loca1->origOffset - loca2->origOffset;
119 static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
120 TrueTypeLoca *loca1 = (TrueTypeLoca *)p1;
121 TrueTypeLoca *loca2 = (TrueTypeLoca *)p2;
123 return loca1->idx - loca2->idx;
126 static int cmpTrueTypeTableTag(const void *p1, const void *p2) {
127 TrueTypeTable *tab1 = (TrueTypeTable *)p1;
128 TrueTypeTable *tab2 = (TrueTypeTable *)p2;
130 return (int)tab1->tag - (int)tab2->tag;
133 //------------------------------------------------------------------------
135 struct T42Table {
136 char *tag; // 4-byte tag
137 GBool required; // required by the TrueType spec?
140 // TrueType tables to be embedded in Type 42 fonts.
141 // NB: the table names must be in alphabetical order here.
142 #define nT42Tables 11
143 static T42Table t42Tables[nT42Tables] = {
144 { "cvt ", gTrue },
145 { "fpgm", gTrue },
146 { "glyf", gTrue },
147 { "head", gTrue },
148 { "hhea", gTrue },
149 { "hmtx", gTrue },
150 { "loca", gTrue },
151 { "maxp", gTrue },
152 { "prep", gTrue },
153 { "vhea", gFalse },
154 { "vmtx", gFalse }
156 #define t42HeadTable 3
157 #define t42LocaTable 6
158 #define t42GlyfTable 2
160 //------------------------------------------------------------------------
162 // Glyph names in some arbitrary standard order that Apple uses for
163 // their TrueType fonts.
164 static char *macGlyphNames[258] = {
165 ".notdef", "null", "CR", "space",
166 "exclam", "quotedbl", "numbersign", "dollar",
167 "percent", "ampersand", "quotesingle", "parenleft",
168 "parenright", "asterisk", "plus", "comma",
169 "hyphen", "period", "slash", "zero",
170 "one", "two", "three", "four",
171 "five", "six", "seven", "eight",
172 "nine", "colon", "semicolon", "less",
173 "equal", "greater", "question", "at",
174 "A", "B", "C", "D",
175 "E", "F", "G", "H",
176 "I", "J", "K", "L",
177 "M", "N", "O", "P",
178 "Q", "R", "S", "T",
179 "U", "V", "W", "X",
180 "Y", "Z", "bracketleft", "backslash",
181 "bracketright", "asciicircum", "underscore", "grave",
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", "braceleft", "bar",
189 "braceright", "asciitilde", "Adieresis", "Aring",
190 "Ccedilla", "Eacute", "Ntilde", "Odieresis",
191 "Udieresis", "aacute", "agrave", "acircumflex",
192 "adieresis", "atilde", "aring", "ccedilla",
193 "eacute", "egrave", "ecircumflex", "edieresis",
194 "iacute", "igrave", "icircumflex", "idieresis",
195 "ntilde", "oacute", "ograve", "ocircumflex",
196 "odieresis", "otilde", "uacute", "ugrave",
197 "ucircumflex", "udieresis", "dagger", "degree",
198 "cent", "sterling", "section", "bullet",
199 "paragraph", "germandbls", "registered", "copyright",
200 "trademark", "acute", "dieresis", "notequal",
201 "AE", "Oslash", "infinity", "plusminus",
202 "lessequal", "greaterequal", "yen", "mu1",
203 "partialdiff", "summation", "product", "pi",
204 "integral", "ordfeminine", "ordmasculine", "Ohm",
205 "ae", "oslash", "questiondown", "exclamdown",
206 "logicalnot", "radical", "florin", "approxequal",
207 "increment", "guillemotleft", "guillemotright", "ellipsis",
208 "nbspace", "Agrave", "Atilde", "Otilde",
209 "OE", "oe", "endash", "emdash",
210 "quotedblleft", "quotedblright", "quoteleft", "quoteright",
211 "divide", "lozenge", "ydieresis", "Ydieresis",
212 "fraction", "currency", "guilsinglleft", "guilsinglright",
213 "fi", "fl", "daggerdbl", "periodcentered",
214 "quotesinglbase", "quotedblbase", "perthousand", "Acircumflex",
215 "Ecircumflex", "Aacute", "Edieresis", "Egrave",
216 "Iacute", "Icircumflex", "Idieresis", "Igrave",
217 "Oacute", "Ocircumflex", "applelogo", "Ograve",
218 "Uacute", "Ucircumflex", "Ugrave", "dotlessi",
219 "circumflex", "tilde", "overscore", "breve",
220 "dotaccent", "ring", "cedilla", "hungarumlaut",
221 "ogonek", "caron", "Lslash", "lslash",
222 "Scaron", "scaron", "Zcaron", "zcaron",
223 "brokenbar", "Eth", "eth", "Yacute",
224 "yacute", "Thorn", "thorn", "minus",
225 "multiply", "onesuperior", "twosuperior", "threesuperior",
226 "onehalf", "onequarter", "threequarters", "franc",
227 "Gbreve", "gbreve", "Idot", "Scedilla",
228 "scedilla", "Cacute", "cacute", "Ccaron",
229 "ccaron", "dmacron"
232 //------------------------------------------------------------------------
233 // FoFiTrueType
234 //------------------------------------------------------------------------
236 FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) {
237 FoFiTrueType *ff;
239 ff = new FoFiTrueType(fileA, lenA, gFalse);
240 if (!ff->parsedOk) {
241 delete ff;
242 return NULL;
244 return ff;
247 FoFiTrueType *FoFiTrueType::load(char *fileName) {
248 FoFiTrueType *ff;
249 char *fileA;
250 int lenA;
252 if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
253 return NULL;
255 ff = new FoFiTrueType(fileA, lenA, gTrue);
256 if (!ff->parsedOk) {
257 delete ff;
258 return NULL;
260 return ff;
263 FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA):
264 FoFiBase(fileA, lenA, freeFileDataA)
266 tables = NULL;
267 nTables = 0;
268 cmaps = NULL;
269 nCmaps = 0;
270 nameToGID = NULL;
271 parsedOk = gFalse;
273 parse();
276 FoFiTrueType::~FoFiTrueType() {
277 gfree(tables);
278 gfree(cmaps);
279 delete nameToGID;
282 int FoFiTrueType::getNumCmaps() {
283 return nCmaps;
286 int FoFiTrueType::getCmapPlatform(int i) {
287 return cmaps[i].platform;
290 int FoFiTrueType::getCmapEncoding(int i) {
291 return cmaps[i].encoding;
294 int FoFiTrueType::findCmap(int platform, int encoding) {
295 int i;
297 for (i = 0; i < nCmaps; ++i) {
298 if (cmaps[i].platform == platform && cmaps[i].encoding == encoding) {
299 return i;
302 return -1;
305 Gushort FoFiTrueType::mapCodeToGID(int i, int c) {
306 Gushort gid;
307 int segCnt, segEnd, segStart, segDelta, segOffset;
308 int cmapFirst, cmapLen;
309 int pos, a, b, m;
310 GBool ok;
312 if (i < 0 || i >= nCmaps) {
313 return 0;
315 ok = gTrue;
316 pos = cmaps[i].offset;
317 switch (cmaps[i].fmt) {
318 case 0:
319 if (c < 0 || c >= cmaps[i].len - 6) {
320 return 0;
322 gid = getU8(cmaps[i].offset + 6 + c, &ok);
323 break;
324 case 4:
325 segCnt = getU16BE(pos + 6, &ok) / 2;
326 a = -1;
327 b = segCnt - 1;
328 segEnd = getU16BE(pos + 14 + 2*b, &ok);
329 if (c > segEnd) {
330 // malformed font -- the TrueType spec requires the last segEnd
331 // to be 0xffff
332 return 0;
334 // invariant: seg[a].end < code <= seg[b].end
335 while (b - a > 1 && ok) {
336 m = (a + b) / 2;
337 segEnd = getU16BE(pos + 14 + 2*m, &ok);
338 if (segEnd < c) {
339 a = m;
340 } else {
341 b = m;
344 segStart = getU16BE(pos + 16 + 2*segCnt + 2*b, &ok);
345 segDelta = getU16BE(pos + 16 + 4*segCnt + 2*b, &ok);
346 segOffset = getU16BE(pos + 16 + 6*segCnt + 2*b, &ok);
347 if (c < segStart) {
348 return 0;
350 if (segOffset == 0) {
351 gid = (c + segDelta) & 0xffff;
352 } else {
353 gid = getU16BE(pos + 16 + 6*segCnt + 2*b +
354 segOffset + 2 * (c - segStart), &ok);
355 if (gid != 0) {
356 gid = (gid + segDelta) & 0xffff;
359 break;
360 case 6:
361 cmapFirst = getU16BE(pos + 6, &ok);
362 cmapLen = getU16BE(pos + 8, &ok);
363 if (c < cmapFirst || c >= cmapFirst + cmapLen) {
364 return 0;
366 gid = getU16BE(pos + 10 + 2 * (c - cmapFirst), &ok);
367 break;
368 default:
369 return 0;
371 if (!ok) {
372 return 0;
374 return gid;
377 int FoFiTrueType::mapNameToGID(char *name) {
378 if (!nameToGID) {
379 return 0;
381 return nameToGID->lookupInt(name);
384 int FoFiTrueType::getEmbeddingRights() {
385 int i, fsType;
386 GBool ok;
388 if ((i = seekTable("OS/2")) < 0) {
389 return 4;
391 ok = gTrue;
392 fsType = getU16BE(tables[i].offset + 8, &ok);
393 if (!ok) {
394 return 4;
396 if (fsType & 0x0008) {
397 return 2;
399 if (fsType & 0x0004) {
400 return 1;
402 if (fsType & 0x0002) {
403 return 0;
405 return 3;
408 void FoFiTrueType::convertToType42(char *psName, char **encoding,
409 Gushort *codeToGID,
410 FoFiOutputFunc outputFunc,
411 void *outputStream) {
412 char buf[512];
413 GBool ok;
415 // write the header
416 ok = gTrue;
417 sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
418 (*outputFunc)(outputStream, buf, strlen(buf));
420 // begin the font dictionary
421 (*outputFunc)(outputStream, "10 dict begin\n", 14);
422 (*outputFunc)(outputStream, "/FontName /", 11);
423 (*outputFunc)(outputStream, psName, strlen(psName));
424 (*outputFunc)(outputStream, " def\n", 5);
425 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
426 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
427 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
428 bbox[0], bbox[1], bbox[2], bbox[3]);
429 (*outputFunc)(outputStream, buf, strlen(buf));
430 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
432 // write the guts of the dictionary
433 cvtEncoding(encoding, outputFunc, outputStream);
434 cvtCharStrings(encoding, codeToGID, outputFunc, outputStream);
435 cvtSfnts(outputFunc, outputStream, NULL);
437 // end the dictionary and define the font
438 (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
441 void FoFiTrueType::convertToCIDType2(char *psName,
442 Gushort *cidMap, int nCIDs,
443 FoFiOutputFunc outputFunc,
444 void *outputStream) {
445 char buf[512];
446 Gushort cid;
447 GBool ok;
448 int i, j, k;
450 // write the header
451 ok = gTrue;
452 sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
453 (*outputFunc)(outputStream, buf, strlen(buf));
455 // begin the font dictionary
456 (*outputFunc)(outputStream, "20 dict begin\n", 14);
457 (*outputFunc)(outputStream, "/CIDFontName /", 14);
458 (*outputFunc)(outputStream, psName, strlen(psName));
459 (*outputFunc)(outputStream, " def\n", 5);
460 (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19);
461 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
462 (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32);
463 (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24);
464 (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27);
465 (*outputFunc)(outputStream, " /Supplement 0 def\n", 20);
466 (*outputFunc)(outputStream, " end def\n", 10);
467 (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
468 if (cidMap) {
469 sprintf(buf, "/CIDCount %d def\n", nCIDs);
470 (*outputFunc)(outputStream, buf, strlen(buf));
471 if (nCIDs > 32767) {
472 (*outputFunc)(outputStream, "/CIDMap [", 9);
473 for (i = 0; i < nCIDs; i += 32768 - 16) {
474 (*outputFunc)(outputStream, "<\n", 2);
475 for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) {
476 (*outputFunc)(outputStream, " ", 2);
477 for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
478 cid = cidMap[i+j+k];
479 sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
480 (*outputFunc)(outputStream, buf, strlen(buf));
482 (*outputFunc)(outputStream, "\n", 1);
484 (*outputFunc)(outputStream, " >", 3);
486 (*outputFunc)(outputStream, "\n", 1);
487 (*outputFunc)(outputStream, "] def\n", 6);
488 } else {
489 (*outputFunc)(outputStream, "/CIDMap <\n", 10);
490 for (i = 0; i < nCIDs; i += 16) {
491 (*outputFunc)(outputStream, " ", 2);
492 for (j = 0; j < 16 && i+j < nCIDs; ++j) {
493 cid = cidMap[i+j];
494 sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
495 (*outputFunc)(outputStream, buf, strlen(buf));
497 (*outputFunc)(outputStream, "\n", 1);
499 (*outputFunc)(outputStream, "> def\n", 6);
501 } else {
502 // direct mapping - just fill the string(s) with s[i]=i
503 sprintf(buf, "/CIDCount %d def\n", nGlyphs);
504 (*outputFunc)(outputStream, buf, strlen(buf));
505 if (nGlyphs > 32767) {
506 (*outputFunc)(outputStream, "/CIDMap [\n", 10);
507 for (i = 0; i < nGlyphs; i += 32767) {
508 j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
509 sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1);
510 (*outputFunc)(outputStream, buf, strlen(buf));
511 sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
512 (*outputFunc)(outputStream, buf, strlen(buf));
513 sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add"
514 " 255 and put\n", i);
515 (*outputFunc)(outputStream, buf, strlen(buf));
516 (*outputFunc)(outputStream, " } for\n", 8);
518 (*outputFunc)(outputStream, "] def\n", 6);
519 } else {
520 sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
521 (*outputFunc)(outputStream, buf, strlen(buf));
522 sprintf(buf, " 0 1 %d {\n", nGlyphs - 1);
523 (*outputFunc)(outputStream, buf, strlen(buf));
524 (*outputFunc)(outputStream,
525 " 2 copy dup 2 mul exch -8 bitshift put\n", 42);
526 (*outputFunc)(outputStream,
527 " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50);
528 (*outputFunc)(outputStream, " } for\n", 8);
529 (*outputFunc)(outputStream, "def\n", 4);
532 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
533 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
534 bbox[0], bbox[1], bbox[2], bbox[3]);
535 (*outputFunc)(outputStream, buf, strlen(buf));
536 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
537 (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
538 (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
539 (*outputFunc)(outputStream, " /.notdef 0 def\n", 17);
540 (*outputFunc)(outputStream, " end readonly def\n", 19);
542 // write the guts of the dictionary
543 cvtSfnts(outputFunc, outputStream, NULL);
545 // end the dictionary and define the font
546 (*outputFunc)(outputStream,
547 "CIDFontName currentdict end /CIDFont defineresource pop\n",
548 56);
551 void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
552 FoFiOutputFunc outputFunc,
553 void *outputStream) {
554 char buf[512];
555 GString *sfntsName;
556 int n, i, j;
558 // write the Type 42 sfnts array
559 sfntsName = (new GString(psName))->append("_sfnts");
560 cvtSfnts(outputFunc, outputStream, sfntsName);
561 delete sfntsName;
563 // write the descendant Type 42 fonts
564 n = cidMap ? nCIDs : nGlyphs;
565 for (i = 0; i < n; i += 256) {
566 (*outputFunc)(outputStream, "10 dict begin\n", 14);
567 (*outputFunc)(outputStream, "/FontName /", 11);
568 (*outputFunc)(outputStream, psName, strlen(psName));
569 sprintf(buf, "_%02x def\n", i >> 8);
570 (*outputFunc)(outputStream, buf, strlen(buf));
571 (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
572 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
573 sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
574 bbox[0], bbox[1], bbox[2], bbox[3]);
575 (*outputFunc)(outputStream, buf, strlen(buf));
576 (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
577 (*outputFunc)(outputStream, "/sfnts ", 7);
578 (*outputFunc)(outputStream, psName, strlen(psName));
579 (*outputFunc)(outputStream, "_sfnts def\n", 11);
580 (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
581 for (j = 0; j < 256 && i+j < n; ++j) {
582 sprintf(buf, "dup %d /c%02x put\n", j, j);
583 (*outputFunc)(outputStream, buf, strlen(buf));
585 (*outputFunc)(outputStream, "readonly def\n", 13);
586 (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
587 (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
588 for (j = 0; j < 256 && i+j < n; ++j) {
589 sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
590 (*outputFunc)(outputStream, buf, strlen(buf));
592 (*outputFunc)(outputStream, "end readonly def\n", 17);
593 (*outputFunc)(outputStream,
594 "FontName currentdict end definefont pop\n", 40);
597 // write the Type 0 parent font
598 (*outputFunc)(outputStream, "16 dict begin\n", 14);
599 (*outputFunc)(outputStream, "/FontName /", 11);
600 (*outputFunc)(outputStream, psName, strlen(psName));
601 (*outputFunc)(outputStream, " def\n", 5);
602 (*outputFunc)(outputStream, "/FontType 0 def\n", 16);
603 (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
604 (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
605 (*outputFunc)(outputStream, "/Encoding [\n", 12);
606 for (i = 0; i < n; i += 256) {
607 sprintf(buf, "%d\n", i >> 8);
608 (*outputFunc)(outputStream, buf, strlen(buf));
610 (*outputFunc)(outputStream, "] def\n", 6);
611 (*outputFunc)(outputStream, "/FDepVector [\n", 14);
612 for (i = 0; i < n; i += 256) {
613 (*outputFunc)(outputStream, "/", 1);
614 (*outputFunc)(outputStream, psName, strlen(psName));
615 sprintf(buf, "_%02x findfont\n", i >> 8);
616 (*outputFunc)(outputStream, buf, strlen(buf));
618 (*outputFunc)(outputStream, "] def\n", 6);
619 (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
622 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
623 void *outputStream) {
624 static char cmapTab[20] = {
625 0, 0, // table version number
626 0, 1, // number of encoding tables
627 0, 1, // platform ID
628 0, 0, // encoding ID
629 0, 0, 0, 12, // offset of subtable
630 0, 0, // subtable format
631 0, 1, // subtable length
632 0, 1, // subtable version
633 0, // map char 0 -> glyph 0
634 0 // pad to multiple of four bytes
636 static char nameTab[8] = {
637 0, 0, // format
638 0, 0, // number of name records
639 0, 6, // offset to start of string storage
640 0, 0 // pad to multiple of four bytes
642 static char postTab[32] = {
643 0, 1, 0, 0, // format
644 0, 0, 0, 0, // italic angle
645 0, 0, // underline position
646 0, 0, // underline thickness
647 0, 0, 0, 0, // fixed pitch
648 0, 0, 0, 0, // min Type 42 memory
649 0, 0, 0, 0, // max Type 42 memory
650 0, 0, 0, 0, // min Type 1 memory
651 0, 0, 0, 0 // max Type 1 memory
653 GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen;
654 int nZeroLengthTables;
655 TrueTypeLoca *locaTable;
656 TrueTypeTable *newTables;
657 int nNewTables, cmapIdx, cmapLen, glyfLen;
658 char *tableDir;
659 char locaBuf[4];
660 GBool ok;
661 Guint t;
662 int pos, i, j, k, n;
664 // check for missing tables
665 missingCmap = (cmapIdx = seekTable("cmap")) < 0;
666 missingName = seekTable("name") < 0;
667 missingPost = seekTable("post") < 0;
669 // read the loca table, check to see if it's sorted
670 locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca));
671 unsortedLoca = gFalse;
672 i = seekTable("loca");
673 pos = tables[i].offset;
674 ok = gTrue;
675 for (i = 0; i <= nGlyphs; ++i) {
676 if (locaFmt) {
677 locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
678 } else {
679 locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
681 if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
682 unsortedLoca = gTrue;
684 locaTable[i].idx = i;
687 // check for zero-length tables
688 nZeroLengthTables = 0;
689 for (i = 0; i < nTables; ++i) {
690 if (tables[i].len == 0) {
691 ++nZeroLengthTables;
695 // check for an incorrect cmap table length
696 badCmapLen = gFalse;
697 cmapLen = 0; // make gcc happy
698 if (!missingCmap) {
699 cmapLen = cmaps[0].offset + cmaps[0].len;
700 for (i = 1; i < nCmaps; ++i) {
701 if (cmaps[i].offset + cmaps[i].len > cmapLen) {
702 cmapLen = cmaps[i].offset + cmaps[i].len;
705 cmapLen -= tables[cmapIdx].offset;
706 if (cmapLen > tables[cmapIdx].len) {
707 badCmapLen = gTrue;
711 // if nothing is broken, just write the TTF file as is
712 if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
713 !badCmapLen && nZeroLengthTables == 0) {
714 (*outputFunc)(outputStream, (char *)file, len);
715 goto done1;
718 // sort the 'loca' table: some (non-compliant) fonts have
719 // out-of-order loca tables; in order to correctly handle the case
720 // where (compliant) fonts have empty entries in the middle of the
721 // table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
722 // and idx as its secondary key (ensuring that adjacent entries with
723 // the same pos value remain in the same order)
724 glyfLen = 0; // make gcc happy
725 if (unsortedLoca) {
726 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
727 &cmpTrueTypeLocaOffset);
728 for (i = 0; i < nGlyphs; ++i) {
729 locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
731 locaTable[nGlyphs].len = 0;
732 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
733 &cmpTrueTypeLocaIdx);
734 pos = 0;
735 for (i = 0; i <= nGlyphs; ++i) {
736 locaTable[i].newOffset = pos;
737 pos += locaTable[i].len;
738 if (pos & 3) {
739 pos += 4 - (pos & 3);
742 glyfLen = pos;
745 // construct the new table directory:
746 // - keep all original tables with non-zero length
747 // - fix the cmap table's length, if necessary
748 // - add missing tables
749 // - sort the table by tag
750 // - compute new table positions, including 4-byte alignment
751 nNewTables = nTables - nZeroLengthTables +
752 (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
753 (missingPost ? 1 : 0);
754 newTables = (TrueTypeTable *)gmalloc(nNewTables * sizeof(TrueTypeTable));
755 j = 0;
756 for (i = 0; i < nTables; ++i) {
757 if (tables[i].len > 0) {
758 newTables[j] = tables[i];
759 newTables[j].origOffset = tables[i].offset;
760 if (newTables[j].tag == cmapTag && badCmapLen) {
761 newTables[j].len = cmapLen;
762 } else if (newTables[j].tag == locaTag && unsortedLoca) {
763 newTables[j].len = (nGlyphs + 1) * (locaFmt ? 4 : 2);
764 } else if (newTables[j].tag == glyfTag && unsortedLoca) {
765 newTables[j].len = glyfLen;
767 ++j;
770 if (missingCmap) {
771 newTables[j].tag = cmapTag;
772 newTables[j].checksum = 0; //~ should compute the checksum
773 newTables[j].len = sizeof(cmapTab);
774 ++j;
776 if (missingName) {
777 newTables[j].tag = nameTag;
778 newTables[j].checksum = 0; //~ should compute the checksum
779 newTables[j].len = sizeof(nameTab);
780 ++j;
782 if (missingPost) {
783 newTables[j].tag = postTag;
784 newTables[j].checksum = 0; //~ should compute the checksum
785 newTables[j].len = sizeof(postTab);
786 ++j;
788 qsort(newTables, nNewTables, sizeof(TrueTypeTable),
789 &cmpTrueTypeTableTag);
790 pos = 12 + nNewTables * 16;
791 for (i = 0; i < nNewTables; ++i) {
792 newTables[i].offset = pos;
793 pos += newTables[i].len;
794 if (pos & 3) {
795 pos += 4 - (pos & 3);
799 // write the table directory
800 tableDir = (char *)gmalloc(12 + nNewTables * 16);
801 tableDir[0] = 0x00; // sfnt version
802 tableDir[1] = 0x01;
803 tableDir[2] = 0x00;
804 tableDir[3] = 0x00;
805 tableDir[4] = (char)((nNewTables >> 8) & 0xff); // numTables
806 tableDir[5] = (char)(nNewTables & 0xff);
807 for (i = -1, t = (Guint)nNewTables; t; ++i, t >>= 1) ;
808 t = 1 << (4 + i);
809 tableDir[6] = (char)((t >> 8) & 0xff); // searchRange
810 tableDir[7] = (char)(t & 0xff);
811 tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector
812 tableDir[9] = (char)(i & 0xff);
813 t = nNewTables * 16 - t;
814 tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift
815 tableDir[11] = (char)(t & 0xff);
816 pos = 12;
817 for (i = 0; i < nNewTables; ++i) {
818 tableDir[pos ] = (char)(newTables[i].tag >> 24);
819 tableDir[pos+ 1] = (char)(newTables[i].tag >> 16);
820 tableDir[pos+ 2] = (char)(newTables[i].tag >> 8);
821 tableDir[pos+ 3] = (char) newTables[i].tag;
822 tableDir[pos+ 4] = (char)(newTables[i].checksum >> 24);
823 tableDir[pos+ 5] = (char)(newTables[i].checksum >> 16);
824 tableDir[pos+ 6] = (char)(newTables[i].checksum >> 8);
825 tableDir[pos+ 7] = (char) newTables[i].checksum;
826 tableDir[pos+ 8] = (char)(newTables[i].offset >> 24);
827 tableDir[pos+ 9] = (char)(newTables[i].offset >> 16);
828 tableDir[pos+10] = (char)(newTables[i].offset >> 8);
829 tableDir[pos+11] = (char) newTables[i].offset;
830 tableDir[pos+12] = (char)(newTables[i].len >> 24);
831 tableDir[pos+13] = (char)(newTables[i].len >> 16);
832 tableDir[pos+14] = (char)(newTables[i].len >> 8);
833 tableDir[pos+15] = (char) newTables[i].len;
834 pos += 16;
836 (*outputFunc)(outputStream, tableDir, 12 + nNewTables * 16);
838 // write the tables
839 for (i = 0; i < nNewTables; ++i) {
840 if (newTables[i].tag == cmapTag && missingCmap) {
841 (*outputFunc)(outputStream, cmapTab, newTables[i].len);
842 } else if (newTables[i].tag == nameTag && missingName) {
843 (*outputFunc)(outputStream, nameTab, newTables[i].len);
844 } else if (newTables[i].tag == postTag && missingPost) {
845 (*outputFunc)(outputStream, postTab, newTables[i].len);
846 } else if (newTables[i].tag == locaTag && unsortedLoca) {
847 for (j = 0; j <= nGlyphs; ++j) {
848 if (locaFmt) {
849 locaBuf[0] = (char)(locaTable[j].newOffset >> 24);
850 locaBuf[1] = (char)(locaTable[j].newOffset >> 16);
851 locaBuf[2] = (char)(locaTable[j].newOffset >> 8);
852 locaBuf[3] = (char) locaTable[j].newOffset;
853 (*outputFunc)(outputStream, locaBuf, 4);
854 } else {
855 locaBuf[0] = (char)(locaTable[j].newOffset >> 9);
856 locaBuf[1] = (char)(locaTable[j].newOffset >> 1);
857 (*outputFunc)(outputStream, locaBuf, 2);
860 } else if (newTables[i].tag == glyfTag && unsortedLoca) {
861 pos = tables[seekTable("glyf")].offset;
862 for (j = 0; j < nGlyphs; ++j) {
863 n = locaTable[j].len;
864 if (n > 0) {
865 k = locaTable[j].origOffset;
866 if (checkRegion(pos + k, n)) {
867 (*outputFunc)(outputStream, (char *)file + pos + k, n);
868 } else {
869 for (k = 0; k < n; ++k) {
870 (*outputFunc)(outputStream, "\0", 1);
873 if ((k = locaTable[j].len & 3)) {
874 (*outputFunc)(outputStream, "\0\0\0\0", 4 - k);
878 } else {
879 if (checkRegion(newTables[i].origOffset, newTables[i].len)) {
880 (*outputFunc)(outputStream, (char *)file + newTables[i].origOffset,
881 newTables[i].len);
882 } else {
883 for (j = 0; j < newTables[i].len; ++j) {
884 (*outputFunc)(outputStream, "\0", 1);
888 if (newTables[i].len & 3) {
889 (*outputFunc)(outputStream, "\0\0\0", 4 - (newTables[i].len & 3));
893 gfree(tableDir);
894 gfree(newTables);
895 done1:
896 gfree(locaTable);
899 void FoFiTrueType::cvtEncoding(char **encoding,
900 FoFiOutputFunc outputFunc,
901 void *outputStream) {
902 char *name;
903 char buf[64];
904 int i;
906 (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
907 if (encoding) {
908 for (i = 0; i < 256; ++i) {
909 if (!(name = encoding[i])) {
910 name = ".notdef";
912 sprintf(buf, "dup %d /", i);
913 (*outputFunc)(outputStream, buf, strlen(buf));
914 (*outputFunc)(outputStream, name, strlen(name));
915 (*outputFunc)(outputStream, " put\n", 5);
917 } else {
918 for (i = 0; i < 256; ++i) {
919 sprintf(buf, "dup %d /c%02x put\n", i, i);
920 (*outputFunc)(outputStream, buf, strlen(buf));
923 (*outputFunc)(outputStream, "readonly def\n", 13);
926 void FoFiTrueType::cvtCharStrings(char **encoding,
927 Gushort *codeToGID,
928 FoFiOutputFunc outputFunc,
929 void *outputStream) {
930 char *name;
931 char buf[64], buf2[16];
932 int i, k;
934 // always define '.notdef'
935 (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32);
936 (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
938 // if there's no 'cmap' table, punt
939 if (nCmaps == 0) {
940 goto err;
943 // map char name to glyph index:
944 // 1. use encoding to map name to char code
945 // 2. use codeToGID to map char code to glyph index
946 // N.B. We do this in reverse order because font subsets can have
947 // weird encodings that use the same character name twice, and
948 // the first definition is probably the one we want.
949 k = 0; // make gcc happy
950 for (i = 255; i >= 0; --i) {
951 if (encoding) {
952 name = encoding[i];
953 } else {
954 sprintf(buf2, "c%02x", i);
955 name = buf2;
957 if (name && strcmp(name, ".notdef")) {
958 k = codeToGID[i];
959 // note: Distiller (maybe Adobe's PS interpreter in general)
960 // doesn't like TrueType fonts that have CharStrings entries
961 // which point to nonexistent glyphs, hence the (k < nGlyphs)
962 // test
963 if (k > 0 && k < nGlyphs) {
964 (*outputFunc)(outputStream, "/", 1);
965 (*outputFunc)(outputStream, name, strlen(name));
966 sprintf(buf, " %d def\n", k);
967 (*outputFunc)(outputStream, buf, strlen(buf));
972 err:
973 (*outputFunc)(outputStream, "end readonly def\n", 17);
976 void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
977 void *outputStream, GString *name) {
978 Guchar headData[54];
979 TrueTypeLoca *locaTable;
980 Guchar *locaData;
981 TrueTypeTable newTables[nT42Tables];
982 Guchar tableDir[12 + nT42Tables*16];
983 GBool ok;
984 Guint checksum;
985 int nNewTables;
986 int length, pos, glyfPos, i, j, k;
988 // construct the 'head' table, zero out the font checksum
989 i = seekTable("head");
990 pos = tables[i].offset;
991 if (!checkRegion(pos, 54)) {
992 return;
994 memcpy(headData, file + pos, 54);
995 headData[8] = headData[9] = headData[10] = headData[11] = (Guchar)0;
997 // read the original 'loca' table, pad entries out to 4 bytes, and
998 // sort it into proper order -- some (non-compliant) fonts have
999 // out-of-order loca tables; in order to correctly handle the case
1000 // where (compliant) fonts have empty entries in the middle of the
1001 // table, cmpTrueTypeLocaPos uses offset as its primary sort key,
1002 // and idx as its secondary key (ensuring that adjacent entries with
1003 // the same pos value remain in the same order)
1004 locaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * sizeof(TrueTypeLoca));
1005 i = seekTable("loca");
1006 pos = tables[i].offset;
1007 ok = gTrue;
1008 for (i = 0; i <= nGlyphs; ++i) {
1009 locaTable[i].idx = i;
1010 if (locaFmt) {
1011 locaTable[i].origOffset = (int)getU32BE(pos + i*4, &ok);
1012 } else {
1013 locaTable[i].origOffset = 2 * getU16BE(pos + i*2, &ok);
1016 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1017 &cmpTrueTypeLocaOffset);
1018 for (i = 0; i < nGlyphs; ++i) {
1019 locaTable[i].len = locaTable[i+1].origOffset - locaTable[i].origOffset;
1021 locaTable[nGlyphs].len = 0;
1022 qsort(locaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
1023 &cmpTrueTypeLocaIdx);
1024 pos = 0;
1025 for (i = 0; i <= nGlyphs; ++i) {
1026 locaTable[i].newOffset = pos;
1027 pos += locaTable[i].len;
1028 if (pos & 3) {
1029 pos += 4 - (pos & 3);
1033 // construct the new 'loca' table
1034 locaData = (Guchar *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
1035 for (i = 0; i <= nGlyphs; ++i) {
1036 pos = locaTable[i].newOffset;
1037 if (locaFmt) {
1038 locaData[4*i ] = (Guchar)(pos >> 24);
1039 locaData[4*i+1] = (Guchar)(pos >> 16);
1040 locaData[4*i+2] = (Guchar)(pos >> 8);
1041 locaData[4*i+3] = (Guchar) pos;
1042 } else {
1043 locaData[2*i ] = (Guchar)(pos >> 9);
1044 locaData[2*i+1] = (Guchar)(pos >> 1);
1048 // count the number of tables
1049 nNewTables = 0;
1050 for (i = 0; i < nT42Tables; ++i) {
1051 if (t42Tables[i].required ||
1052 seekTable(t42Tables[i].tag) >= 0) {
1053 ++nNewTables;
1057 // construct the new table headers, including table checksums
1058 // (pad each table out to a multiple of 4 bytes)
1059 pos = 12 + nNewTables*16;
1060 k = 0;
1061 for (i = 0; i < nT42Tables; ++i) {
1062 length = -1;
1063 checksum = 0; // make gcc happy
1064 if (i == t42HeadTable) {
1065 length = 54;
1066 checksum = computeTableChecksum(headData, 54);
1067 } else if (i == t42LocaTable) {
1068 length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1069 checksum = computeTableChecksum(locaData, length);
1070 } else if (i == t42GlyfTable) {
1071 length = 0;
1072 checksum = 0;
1073 glyfPos = tables[seekTable("glyf")].offset;
1074 for (j = 0; j < nGlyphs; ++j) {
1075 length += locaTable[j].len;
1076 if (length & 3) {
1077 length += 4 - (length & 3);
1079 if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1080 checksum +=
1081 computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
1082 locaTable[j].len);
1085 } else {
1086 if ((j = seekTable(t42Tables[i].tag)) >= 0) {
1087 length = tables[j].len;
1088 if (checkRegion(tables[j].offset, length)) {
1089 checksum = computeTableChecksum(file + tables[j].offset, length);
1091 } else if (t42Tables[i].required) {
1092 //~ error(-1, "Embedded TrueType font is missing a required table ('%s')",
1093 //~ t42Tables[i].tag);
1094 length = 0;
1095 checksum = 0;
1098 if (length >= 0) {
1099 newTables[k].tag = ((t42Tables[i].tag[0] & 0xff) << 24) |
1100 ((t42Tables[i].tag[1] & 0xff) << 16) |
1101 ((t42Tables[i].tag[2] & 0xff) << 8) |
1102 (t42Tables[i].tag[3] & 0xff);
1103 newTables[k].checksum = checksum;
1104 newTables[k].offset = pos;
1105 newTables[k].len = length;
1106 pos += length;
1107 if (pos & 3) {
1108 pos += 4 - (length & 3);
1110 ++k;
1114 // construct the table directory
1115 tableDir[0] = 0x00; // sfnt version
1116 tableDir[1] = 0x01;
1117 tableDir[2] = 0x00;
1118 tableDir[3] = 0x00;
1119 tableDir[4] = 0; // numTables
1120 tableDir[5] = nNewTables;
1121 tableDir[6] = 0; // searchRange
1122 tableDir[7] = (Guchar)128;
1123 tableDir[8] = 0; // entrySelector
1124 tableDir[9] = 3;
1125 tableDir[10] = 0; // rangeShift
1126 tableDir[11] = (Guchar)(16 * nNewTables - 128);
1127 pos = 12;
1128 for (i = 0; i < nNewTables; ++i) {
1129 tableDir[pos ] = (Guchar)(newTables[i].tag >> 24);
1130 tableDir[pos+ 1] = (Guchar)(newTables[i].tag >> 16);
1131 tableDir[pos+ 2] = (Guchar)(newTables[i].tag >> 8);
1132 tableDir[pos+ 3] = (Guchar) newTables[i].tag;
1133 tableDir[pos+ 4] = (Guchar)(newTables[i].checksum >> 24);
1134 tableDir[pos+ 5] = (Guchar)(newTables[i].checksum >> 16);
1135 tableDir[pos+ 6] = (Guchar)(newTables[i].checksum >> 8);
1136 tableDir[pos+ 7] = (Guchar) newTables[i].checksum;
1137 tableDir[pos+ 8] = (Guchar)(newTables[i].offset >> 24);
1138 tableDir[pos+ 9] = (Guchar)(newTables[i].offset >> 16);
1139 tableDir[pos+10] = (Guchar)(newTables[i].offset >> 8);
1140 tableDir[pos+11] = (Guchar) newTables[i].offset;
1141 tableDir[pos+12] = (Guchar)(newTables[i].len >> 24);
1142 tableDir[pos+13] = (Guchar)(newTables[i].len >> 16);
1143 tableDir[pos+14] = (Guchar)(newTables[i].len >> 8);
1144 tableDir[pos+15] = (Guchar) newTables[i].len;
1145 pos += 16;
1148 // compute the font checksum and store it in the head table
1149 checksum = computeTableChecksum(tableDir, 12 + nNewTables*16);
1150 for (i = 0; i < nNewTables; ++i) {
1151 checksum += newTables[i].checksum;
1153 checksum = 0xb1b0afba - checksum; // because the TrueType spec says so
1154 headData[ 8] = (Guchar)(checksum >> 24);
1155 headData[ 9] = (Guchar)(checksum >> 16);
1156 headData[10] = (Guchar)(checksum >> 8);
1157 headData[11] = (Guchar) checksum;
1159 // start the sfnts array
1160 if (name) {
1161 (*outputFunc)(outputStream, "/", 1);
1162 (*outputFunc)(outputStream, name->getCString(), name->getLength());
1163 (*outputFunc)(outputStream, " [\n", 3);
1164 } else {
1165 (*outputFunc)(outputStream, "/sfnts [\n", 9);
1168 // write the table directory
1169 dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream);
1171 // write the tables
1172 for (i = 0; i < nNewTables; ++i) {
1173 if (i == t42HeadTable) {
1174 dumpString(headData, 54, outputFunc, outputStream);
1175 } else if (i == t42LocaTable) {
1176 length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
1177 dumpString(locaData, length, outputFunc, outputStream);
1178 } else if (i == t42GlyfTable) {
1179 glyfPos = tables[seekTable("glyf")].offset;
1180 for (j = 0; j < nGlyphs; ++j) {
1181 if (locaTable[j].len > 0 &&
1182 checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
1183 dumpString(file + glyfPos + locaTable[j].origOffset,
1184 locaTable[j].len, outputFunc, outputStream);
1187 } else {
1188 // length == 0 means the table is missing and the error was
1189 // already reported during the construction of the table
1190 // headers
1191 if ((length = newTables[i].len) > 0) {
1192 if ((j = seekTable(t42Tables[i].tag)) >= 0 &&
1193 checkRegion(tables[j].offset, tables[j].len)) {
1194 dumpString(file + tables[j].offset, tables[j].len,
1195 outputFunc, outputStream);
1201 // end the sfnts array
1202 (*outputFunc)(outputStream, "] def\n", 6);
1204 gfree(locaData);
1205 gfree(locaTable);
1208 void FoFiTrueType::dumpString(Guchar *s, int length,
1209 FoFiOutputFunc outputFunc,
1210 void *outputStream) {
1211 char buf[64];
1212 int pad, i, j;
1214 (*outputFunc)(outputStream, "<", 1);
1215 for (i = 0; i < length; i += 32) {
1216 for (j = 0; j < 32 && i+j < length; ++j) {
1217 sprintf(buf, "%02X", s[i+j] & 0xff);
1218 (*outputFunc)(outputStream, buf, strlen(buf));
1220 if (i % (65536 - 32) == 65536 - 64) {
1221 (*outputFunc)(outputStream, ">\n<", 3);
1222 } else if (i+32 < length) {
1223 (*outputFunc)(outputStream, "\n", 1);
1226 if (length & 3) {
1227 pad = 4 - (length & 3);
1228 for (i = 0; i < pad; ++i) {
1229 (*outputFunc)(outputStream, "00", 2);
1232 // add an extra zero byte because the Adobe Type 42 spec says so
1233 (*outputFunc)(outputStream, "00>\n", 4);
1236 Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
1237 Guint checksum, word;
1238 int i;
1240 checksum = 0;
1241 for (i = 0; i+3 < length; i += 4) {
1242 word = ((data[i ] & 0xff) << 24) +
1243 ((data[i+1] & 0xff) << 16) +
1244 ((data[i+2] & 0xff) << 8) +
1245 (data[i+3] & 0xff);
1246 checksum += word;
1248 if (length & 3) {
1249 word = 0;
1250 i = length & ~3;
1251 switch (length & 3) {
1252 case 3:
1253 word |= (data[i+2] & 0xff) << 8;
1254 case 2:
1255 word |= (data[i+1] & 0xff) << 16;
1256 case 1:
1257 word |= (data[i ] & 0xff) << 24;
1258 break;
1260 checksum += word;
1262 return checksum;
1265 void FoFiTrueType::parse() {
1266 int pos, i, j;
1268 parsedOk = gTrue;
1270 // read the table directory
1271 nTables = getU16BE(4, &parsedOk);
1272 if (!parsedOk) {
1273 return;
1275 tables = (TrueTypeTable *)gmalloc(nTables * sizeof(TrueTypeTable));
1276 pos = 12;
1277 for (i = 0; i < nTables; ++i) {
1278 tables[i].tag = getU32BE(pos, &parsedOk);
1279 tables[i].checksum = getU32BE(pos + 4, &parsedOk);
1280 tables[i].offset = (int)getU32BE(pos + 8, &parsedOk);
1281 tables[i].len = (int)getU32BE(pos + 12, &parsedOk);
1282 if (tables[i].offset + tables[i].len < tables[i].offset ||
1283 tables[i].offset + tables[i].len > len) {
1284 parsedOk = gFalse;
1286 pos += 16;
1288 if (!parsedOk) {
1289 return;
1292 // check for tables that are required by both the TrueType spec and
1293 // the Type 42 spec
1294 if (seekTable("head") < 0 ||
1295 seekTable("hhea") < 0 ||
1296 seekTable("loca") < 0 ||
1297 seekTable("maxp") < 0 ||
1298 seekTable("glyf") < 0 ||
1299 seekTable("hmtx") < 0) {
1300 parsedOk = gFalse;
1301 return;
1304 // read the cmaps
1305 if ((i = seekTable("cmap")) >= 0) {
1306 pos = tables[i].offset + 2;
1307 nCmaps = getU16BE(pos, &parsedOk);
1308 pos += 2;
1309 if (!parsedOk) {
1310 return;
1312 cmaps = (TrueTypeCmap *)gmalloc(nCmaps * sizeof(TrueTypeCmap));
1313 for (j = 0; j < nCmaps; ++j) {
1314 cmaps[j].platform = getU16BE(pos, &parsedOk);
1315 cmaps[j].encoding = getU16BE(pos + 2, &parsedOk);
1316 cmaps[j].offset = tables[i].offset + getU32BE(pos + 4, &parsedOk);
1317 pos += 8;
1318 cmaps[j].fmt = getU16BE(cmaps[j].offset, &parsedOk);
1319 cmaps[j].len = getU16BE(cmaps[j].offset + 2, &parsedOk);
1321 if (!parsedOk) {
1322 return;
1324 } else {
1325 nCmaps = 0;
1328 // get the number of glyphs from the maxp table
1329 i = seekTable("maxp");
1330 nGlyphs = getU16BE(tables[i].offset + 4, &parsedOk);
1331 if (!parsedOk) {
1332 return;
1335 // get the bbox and loca table format from the head table
1336 i = seekTable("head");
1337 bbox[0] = getS16BE(tables[i].offset + 36, &parsedOk);
1338 bbox[1] = getS16BE(tables[i].offset + 38, &parsedOk);
1339 bbox[2] = getS16BE(tables[i].offset + 40, &parsedOk);
1340 bbox[3] = getS16BE(tables[i].offset + 42, &parsedOk);
1341 locaFmt = getS16BE(tables[i].offset + 50, &parsedOk);
1342 if (!parsedOk) {
1343 return;
1346 // read the post table
1347 readPostTable();
1348 if (!parsedOk) {
1349 return;
1353 void FoFiTrueType::readPostTable() {
1354 GString *name;
1355 int tablePos, postFmt, stringIdx, stringPos;
1356 int i, j, n, m;
1358 if ((i = seekTable("post")) < 0) {
1359 return;
1361 tablePos = tables[i].offset;
1362 postFmt = getU32BE(tablePos, &parsedOk);
1363 if (!parsedOk) {
1364 return;
1366 if (postFmt == 0x00010000) {
1367 nameToGID = new GHash(gTrue);
1368 for (i = 0; i < 258; ++i) {
1369 nameToGID->add(new GString(macGlyphNames[i]), i);
1371 } else if (postFmt == 0x00020000) {
1372 nameToGID = new GHash(gTrue);
1373 n = getU16BE(tablePos + 32, &parsedOk);
1374 if (!parsedOk) {
1375 return;
1377 if (n > nGlyphs) {
1378 n = nGlyphs;
1380 stringIdx = 0;
1381 stringPos = tablePos + 34 + 2*n;
1382 for (i = 0; i < n; ++i) {
1383 j = getU16BE(tablePos + 34 + 2*i, &parsedOk);
1384 if (j < 258) {
1385 nameToGID->removeInt(macGlyphNames[j]);
1386 nameToGID->add(new GString(macGlyphNames[j]), i);
1387 } else {
1388 j -= 258;
1389 if (j != stringIdx) {
1390 for (stringIdx = 0, stringPos = tablePos + 34 + 2*n;
1391 stringIdx < j;
1392 ++stringIdx, stringPos += 1 + getU8(stringPos, &parsedOk)) ;
1393 if (!parsedOk) {
1394 return;
1397 m = getU8(stringPos, &parsedOk);
1398 if (!parsedOk || !checkRegion(stringPos + 1, m)) {
1399 parsedOk = gFalse;
1400 return;
1402 name = new GString((char *)&file[stringPos + 1], m);
1403 nameToGID->removeInt(name);
1404 nameToGID->add(name, i);
1405 ++stringIdx;
1406 stringPos += 1 + m;
1409 } else if (postFmt == 0x00028000) {
1410 nameToGID = new GHash(gTrue);
1411 for (i = 0; i < nGlyphs; ++i) {
1412 j = getU8(tablePos + 32 + i, &parsedOk);
1413 if (!parsedOk) {
1414 return;
1416 if (j < 258) {
1417 nameToGID->removeInt(macGlyphNames[j]);
1418 nameToGID->add(new GString(macGlyphNames[j]), i);
1424 int FoFiTrueType::seekTable(char *tag) {
1425 Guint tagI;
1426 int i;
1428 tagI = ((tag[0] & 0xff) << 24) |
1429 ((tag[1] & 0xff) << 16) |
1430 ((tag[2] & 0xff) << 8) |
1431 (tag[3] & 0xff);
1432 for (i = 0; i < nTables; ++i) {
1433 if (tables[i].tag == tagI) {
1434 return i;
1437 return -1;