[poppler] poppler/fofi: FoFiTrueType.cc, 1.5, 1.6 FoFiTrueType.h, 1.3, 1.4 FoFiType1.cc, 1.5, 1.6 FoFiType1C.cc, 1.3, 1.4 FoFiType1C.h, 1.3, 1.4

Albert Astals Cid aacid at kemper.freedesktop.org
Wed Apr 25 12:59:12 PDT 2007


Update of /cvs/poppler/poppler/fofi
In directory kemper:/tmp/cvs-serv1447/fofi

Modified Files:
	FoFiTrueType.cc FoFiTrueType.h FoFiType1.cc FoFiType1C.cc 
	FoFiType1C.h 
Log Message:
Merge xpdf302branch in HEAD as noone vetoed it.
Testing more than welcome


Index: FoFiTrueType.cc
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiTrueType.cc,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- FoFiTrueType.cc	2 Feb 2006 22:50:01 -0000	1.5
+++ FoFiTrueType.cc	25 Apr 2007 19:59:10 -0000	1.6
@@ -18,6 +18,7 @@
 #include "goo/gmem.h"
 #include "goo/GooString.h"
 #include "goo/GooHash.h"
+#include "FoFiType1C.h"
 #include "FoFiTrueType.h"
 
 //
@@ -108,8 +109,11 @@
 #define cmapTag 0x636d6170
 #define glyfTag 0x676c7966
 #define headTag 0x68656164
+#define hheaTag 0x68686561
+#define hmtxTag 0x686d7478
 #define locaTag 0x6c6f6361
 #define nameTag 0x6e616d65
+#define os2Tag  0x4f532f32
 #define postTag 0x706f7374
 
 static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
@@ -392,6 +396,28 @@
   return nameToGID->lookupInt(name);
 }
 
+Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) {
+  FoFiType1C *ff;
+  Gushort *map;
+  int i;
+
+  *nCIDs = 0;
+  if (!openTypeCFF) {
+    return NULL;
+  }
+  i = seekTable("CFF ");
+  if (!checkRegion(tables[i].offset, tables[i].len)) {
+    return NULL;
+  }
+  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+			      tables[i].len))) {
+    return NULL;
+  }
+  map = ff->getCIDToGIDMap(nCIDs);
+  delete ff;
+  return map;
+}
+
 int FoFiTrueType::getEmbeddingRights() {
   int i, fsType;
   GBool ok;
@@ -420,13 +446,19 @@
 				   Gushort *codeToGID,
 				   FoFiOutputFunc outputFunc,
 				   void *outputStream) {
-  char buf[512];
+  GooString *buf;
   GBool ok;
 
+  if (openTypeCFF) {
+    return;
+  }
+
   // write the header
   ok = gTrue;
-  sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
-  (*outputFunc)(outputStream, buf, strlen(buf));
+  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
+			(double)getS32BE(0, &ok) / 65536.0);
+  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+  delete buf;
 
   // begin the font dictionary
   (*outputFunc)(outputStream, "10 dict begin\n", 14);
@@ -435,9 +467,10 @@
   (*outputFunc)(outputStream, " def\n", 5);
   (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
   (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
-  sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
-	  bbox[0], bbox[1], bbox[2], bbox[3]);
-  (*outputFunc)(outputStream, buf, strlen(buf));
+  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+			bbox[0], bbox[1], bbox[2], bbox[3]);
+  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+  delete buf;
   (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
 
   // write the guts of the dictionary
@@ -449,20 +482,47 @@
   (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
 }
 
+void FoFiTrueType::convertToType1(char *psName, char **newEncoding,
+				  GBool ascii, FoFiOutputFunc outputFunc,
+				  void *outputStream) {
+  FoFiType1C *ff;
+  int i;
+
+  if (!openTypeCFF) {
+    return;
+  }
+  i = seekTable("CFF ");
+  if (!checkRegion(tables[i].offset, tables[i].len)) {
+    return;
+  }
+  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+			      tables[i].len))) {
+    return;
+  }
+  ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream);
+  delete ff;
+}
+
 void FoFiTrueType::convertToCIDType2(char *psName,
 				     Gushort *cidMap, int nCIDs,
 				     GBool needVerticalMetrics,
 				     FoFiOutputFunc outputFunc,
 				     void *outputStream) {
-  char buf[512];
+  GooString *buf;
   Gushort cid;
   GBool ok;
   int i, j, k;
 
+  if (openTypeCFF) {
+    return;
+  }
+
   // write the header
   ok = gTrue;
-  sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
-  (*outputFunc)(outputStream, buf, strlen(buf));
+  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
+			(double)getS32BE(0, &ok) / 65536.0);
+  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+  delete buf;
 
   // begin the font dictionary
   (*outputFunc)(outputStream, "20 dict begin\n", 14);
@@ -478,8 +538,9 @@
   (*outputFunc)(outputStream, "  end def\n", 10);
   (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
   if (cidMap) {
-    sprintf(buf, "/CIDCount %d def\n", nCIDs);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("/CIDCount {0:d} def\n", nCIDs);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
     if (nCIDs > 32767) {
       (*outputFunc)(outputStream, "/CIDMap [", 9);
       for (i = 0; i < nCIDs; i += 32768 - 16) {
@@ -488,8 +549,10 @@
 	  (*outputFunc)(outputStream, "  ", 2);
 	  for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
 	    cid = cidMap[i+j+k];
-	    sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
-	    (*outputFunc)(outputStream, buf, strlen(buf));
+	    buf = GooString::format("{0:02x}{1:02x}",
+				  (cid >> 8) & 0xff, cid & 0xff);
+	    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	    delete buf;
 	  }
 	  (*outputFunc)(outputStream, "\n", 1);
 	}
@@ -503,8 +566,10 @@
 	(*outputFunc)(outputStream, "  ", 2);
 	for (j = 0; j < 16 && i+j < nCIDs; ++j) {
 	  cid = cidMap[i+j];
-	  sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
-	  (*outputFunc)(outputStream, buf, strlen(buf));
+	  buf = GooString::format("{0:02x}{1:02x}",
+				(cid >> 8) & 0xff, cid & 0xff);
+	  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	  delete buf;
 	}
 	(*outputFunc)(outputStream, "\n", 1);
       }
@@ -512,27 +577,34 @@
     }
   } else {
     // direct mapping - just fill the string(s) with s[i]=i
-    sprintf(buf, "/CIDCount %d def\n", nGlyphs);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("/CIDCount {0:d} def\n", nGlyphs);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
     if (nGlyphs > 32767) {
       (*outputFunc)(outputStream, "/CIDMap [\n", 10);
       for (i = 0; i < nGlyphs; i += 32767) {
 	j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
-	sprintf(buf, "  %d string 0 1 %d {\n", 2 * j, j - 1);
-	(*outputFunc)(outputStream, buf, strlen(buf));
-	sprintf(buf, "    2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
-	(*outputFunc)(outputStream, buf, strlen(buf));
-	sprintf(buf, "    1 index exch dup 2 mul 1 add exch %d add"
-		" 255 and put\n", i);
-	(*outputFunc)(outputStream, buf, strlen(buf));
+	buf = GooString::format("  {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
+	buf = GooString::format("    2 copy dup 2 mul exch {0:d} add -8 bitshift put\n",
+			      i);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
+	buf = GooString::format("    1 index exch dup 2 mul 1 add exch {0:d} add"
+			      " 255 and put\n", i);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
 	(*outputFunc)(outputStream, "  } for\n", 8);
       }
       (*outputFunc)(outputStream, "] def\n", 6);
     } else {
-      sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
-      (*outputFunc)(outputStream, buf, strlen(buf));
-      sprintf(buf, "  0 1 %d {\n", nGlyphs - 1);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("/CIDMap {0:d} string\n", 2 * nGlyphs);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
+      buf = GooString::format("  0 1 {0:d} {{\n", nGlyphs - 1);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
       (*outputFunc)(outputStream,
 		    "    2 copy dup 2 mul exch -8 bitshift put\n", 42);
       (*outputFunc)(outputStream,
@@ -542,9 +614,10 @@
     }
   }
   (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
-  sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
-	  bbox[0], bbox[1], bbox[2], bbox[3]);
-  (*outputFunc)(outputStream, buf, strlen(buf));
+  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+			bbox[0], bbox[1], bbox[2], bbox[3]);
+  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+  delete buf;
   (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
   (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
   (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
@@ -560,14 +633,39 @@
 		56);
 }
 
+void FoFiTrueType::convertToCIDType0(char *psName,
+				     FoFiOutputFunc outputFunc,
+				     void *outputStream) {
+  FoFiType1C *ff;
+  int i;
+
+  if (!openTypeCFF) {
+    return;
+  }
+  i = seekTable("CFF ");
+  if (!checkRegion(tables[i].offset, tables[i].len)) {
+    return;
+  }
+  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+			      tables[i].len))) {
+    return;
+  }
+  ff->convertToCIDType0(psName, outputFunc, outputStream);
+  delete ff;
+}
+
 void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
 				  GBool needVerticalMetrics,
 				  FoFiOutputFunc outputFunc,
 				  void *outputStream) {
-  char buf[512];
+  GooString *buf;
   GooString *sfntsName;
   int n, i, j;
 
+  if (openTypeCFF) {
+    return;
+  }
+
   // write the Type 42 sfnts array
   sfntsName = (new GooString(psName))->append("_sfnts");
   cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
@@ -579,28 +677,33 @@
     (*outputFunc)(outputStream, "10 dict begin\n", 14);
     (*outputFunc)(outputStream, "/FontName /", 11);
     (*outputFunc)(outputStream, psName, strlen(psName));
-    sprintf(buf, "_%02x def\n", i >> 8);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("_{0:02x} def\n", i >> 8);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
     (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
     (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
-    sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
-	    bbox[0], bbox[1], bbox[2], bbox[3]);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+			  bbox[0], bbox[1], bbox[2], bbox[3]);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
     (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
     (*outputFunc)(outputStream, "/sfnts ", 7);
     (*outputFunc)(outputStream, psName, strlen(psName));
     (*outputFunc)(outputStream, "_sfnts def\n", 11);
     (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
     for (j = 0; j < 256 && i+j < n; ++j) {
-      sprintf(buf, "dup %d /c%02x put\n", j, j);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("dup {0:d} /c{1:02x} put\n", j, j);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
     }
     (*outputFunc)(outputStream, "readonly def\n", 13);
     (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
     (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
     for (j = 0; j < 256 && i+j < n; ++j) {
-      sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("/c{0:02x} {1:d} def\n",
+			    j, cidMap ? cidMap[i+j] : i+j);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
     }
     (*outputFunc)(outputStream, "end readonly def\n", 17);
     (*outputFunc)(outputStream,
@@ -617,21 +720,44 @@
   (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
   (*outputFunc)(outputStream, "/Encoding [\n", 12);
   for (i = 0; i < n; i += 256) {
-    sprintf(buf, "%d\n", i >> 8);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("{0:d}\n", i >> 8);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
   }
   (*outputFunc)(outputStream, "] def\n", 6);
   (*outputFunc)(outputStream, "/FDepVector [\n", 14);
   for (i = 0; i < n; i += 256) {
     (*outputFunc)(outputStream, "/", 1);
     (*outputFunc)(outputStream, psName, strlen(psName));
-    sprintf(buf, "_%02x findfont\n", i >> 8);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("_{0:02x} findfont\n", i >> 8);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
   }
   (*outputFunc)(outputStream, "] def\n", 6);
   (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
 }
 
+void FoFiTrueType::convertToType0(char *psName,
+				  FoFiOutputFunc outputFunc,
+				  void *outputStream) {
+  FoFiType1C *ff;
+  int i;
+
+  if (!openTypeCFF) {
+    return;
+  }
+  i = seekTable("CFF ");
+  if (!checkRegion(tables[i].offset, tables[i].len)) {
+    return;
+  }
+  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+			      tables[i].len))) {
+    return;
+  }
+  ff->convertToType0(psName, outputFunc, outputStream);
+  delete ff;
+}
+
 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
 			    void *outputStream, char *name,
 			    Gushort *codeToGID) {
@@ -673,12 +799,50 @@
     0, 0, 0, 0,			// min Type 1 memory
     0, 0, 0, 0			// max Type 1 memory
   };
-  GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen;
+  static char os2Tab[86] = {
+    0, 1,			// version
+    0, 1,			// xAvgCharWidth
+    0, 0,			// usWeightClass
+    0, 0,			// usWidthClass
+    0, 0,			// fsType
+    0, 0,			// ySubscriptXSize
+    0, 0,			// ySubscriptYSize
+    0, 0,			// ySubscriptXOffset
+    0, 0,			// ySubscriptYOffset
+    0, 0,			// ySuperscriptXSize
+    0, 0,			// ySuperscriptYSize
+    0, 0,			// ySuperscriptXOffset
+    0, 0,			// ySuperscriptYOffset
+    0, 0,			// yStrikeoutSize
+    0, 0,			// yStrikeoutPosition
+    0, 0,			// sFamilyClass
+    0, 0, 0, 0, 0,		// panose
+    0, 0, 0, 0, 0,
+    0, 0, 0, 0,			// ulUnicodeRange1
+    0, 0, 0, 0,			// ulUnicodeRange2
+    0, 0, 0, 0,			// ulUnicodeRange3
+    0, 0, 0, 0,			// ulUnicodeRange4
+    0, 0, 0, 0,			// achVendID
+    0, 0,			// fsSelection
+    0, 0,			// usFirstCharIndex
+    0, 0,			// usLastCharIndex
+    0, 0,			// sTypoAscender
+    0, 0,			// sTypoDescender
+    0, 0,			// sTypoLineGap
+    0, 0,			// usWinAscent
+    0, 0,			// usWinDescent
+    0, 0, 0, 0,			// ulCodePageRange1
+    0, 0, 0, 0			// ulCodePageRange2
+  };
+  GBool missingCmap, missingName, missingPost, missingOS2;
+  GBool unsortedLoca, badCmapLen, abbrevHMTX;
   int nZeroLengthTables;
+  int nHMetrics, advWidth, lsb;
   TrueTypeLoca *locaTable;
   TrueTypeTable *newTables;
-  char *newNameTab, *newCmapTab;
+  char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab;
   int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
+  int newHHEALen, newHMTXLen;
   Guint locaChecksum, glyfChecksum, fileChecksum;
   char *tableDir;
   char locaBuf[4], checksumBuf[4];
@@ -686,10 +850,20 @@
   Guint t;
   int pos, i, j, k, n;
 
+  if (openTypeCFF) {
+    return;
+  }
+
   // check for missing tables
+  // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver
+  // will embed a PCL TrueType font with the pitch field set to zero,
+  // which apparently causes divide-by-zero errors.  As far as I can
+  // tell, the only important field in the OS/2 table is
+  // xAvgCharWidth.)
   missingCmap = (cmapIdx = seekTable("cmap")) < 0;
   missingName = seekTable("name") < 0;
   missingPost = seekTable("post") < 0;
+  missingOS2 = seekTable("OS/2") < 0;
 
   // read the loca table, check to see if it's sorted
   locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
@@ -706,6 +880,19 @@
     if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
       unsortedLoca = gTrue;
     }
+    // glyph descriptions must be at least 12 bytes long (nContours,
+    // xMin, yMin, xMax, yMax, instructionLength - two bytes each);
+    // invalid glyph descriptions (even if they're never used) make
+    // Windows choke, so we work around that problem here (ideally,
+    // this would parse the glyph descriptions in the glyf table and
+    // remove any that were invalid, but this quick test is a decent
+    // start)
+    if (i > 0 &&
+	locaTable[i].origOffset - locaTable[i-1].origOffset > 0 &&
+	locaTable[i].origOffset - locaTable[i-1].origOffset < 12) {
+      locaTable[i-1].origOffset = locaTable[i].origOffset;
+      unsortedLoca = gTrue;
+    }
     locaTable[i].idx = i;
   }
 
@@ -733,9 +920,17 @@
     }
   }
 
+  // check for an abbreviated hmtx table (this is completely legal,
+  // but confuses the Microsoft PCL5 printer driver, which generates
+  // embedded fonts with the pitch field set to zero)
+  i = seekTable("hhea");
+  nHMetrics = getU16BE(tables[i].offset + 34, &ok);
+  abbrevHMTX = nHMetrics < nGlyphs;
+
   // if nothing is broken, just write the TTF file as is
-  if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
-      !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) {
+  if (!missingCmap && !missingName && !missingPost && !missingOS2 &&
+      !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 &&
+      !name && !codeToGID) {
     (*outputFunc)(outputStream, (char *)file, len);
     goto done1;
   }
@@ -893,6 +1088,44 @@
     newCmapTab = NULL;
   }
 
+  // generate the new hmtx table and the updated hhea table
+  if (abbrevHMTX) {
+    i = seekTable("hhea");
+    pos = tables[i].offset;
+    newHHEALen = 36;
+    newHHEATab = (char *)gmalloc(newHHEALen);
+    for (i = 0; i < newHHEALen; ++i) {
+      newHHEATab[i] = getU8(pos++, &ok);
+    }
+    newHHEATab[34] = nGlyphs >> 8;
+    newHHEATab[35] = nGlyphs & 0xff;
+    i = seekTable("hmtx");
+    pos = tables[i].offset;
+    newHMTXLen = 4 * nGlyphs;
+    newHMTXTab = (char *)gmalloc(newHMTXLen);
+    advWidth = 0;
+    for (i = 0; i < nHMetrics; ++i) {
+      advWidth = getU16BE(pos, &ok);
+      lsb = getU16BE(pos + 2, &ok);
+      pos += 4;
+      newHMTXTab[4*i    ] = advWidth >> 8;
+      newHMTXTab[4*i + 1] = advWidth & 0xff;
+      newHMTXTab[4*i + 2] = lsb >> 8;
+      newHMTXTab[4*i + 3] = lsb & 0xff;
+    }
+    for (; i < nGlyphs; ++i) {
+      lsb = getU16BE(pos, &ok);
+      pos += 2;
+      newHMTXTab[4*i    ] = advWidth >> 8;
+      newHMTXTab[4*i + 1] = advWidth & 0xff;
+      newHMTXTab[4*i + 2] = lsb >> 8;
+      newHMTXTab[4*i + 3] = lsb & 0xff;
+    }
+  } else {
+    newHHEATab = newHMTXTab = NULL;
+    newHHEALen = newHMTXLen = 0; // make gcc happy
+  }
+
   // construct the new table directory:
   // - keep all original tables with non-zero length
   // - fix the cmap table's length, if necessary
@@ -902,7 +1135,7 @@
   // - (re)compute table checksums
   nNewTables = nTables - nZeroLengthTables +
                (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
-               (missingPost ? 1 : 0);
+               (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0);
   newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
   j = 0;
   for (i = 0; i < nTables; ++i) {
@@ -933,6 +1166,14 @@
 	newTables[j].len = newNameLen;
 	newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
 						     newNameLen);
+      } else if (newTables[j].tag == hheaTag && abbrevHMTX) {
+	newTables[j].len = newHHEALen;
+	newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab,
+						     newHHEALen);
+      } else if (newTables[j].tag == hmtxTag && abbrevHMTX) {
+	newTables[j].len = newHMTXLen;
+	newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab,
+						     newHMTXLen);
       }
       ++j;
     }
@@ -970,6 +1211,13 @@
     newTables[j].len = sizeof(postTab);
     ++j;
   }
+  if (missingOS2) {
+    newTables[j].tag = os2Tag;
+    newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab,
+						 sizeof(os2Tab));
+    newTables[j].len = sizeof(os2Tab);
+    ++j;
+  }
   qsort(newTables, nNewTables, sizeof(TrueTypeTable),
 	&cmpTrueTypeTableTag);
   pos = 12 + nNewTables * 16;
@@ -1056,6 +1304,12 @@
       (*outputFunc)(outputStream, nameTab, newTables[i].len);
     } else if (newTables[i].tag == postTag && missingPost) {
       (*outputFunc)(outputStream, postTab, newTables[i].len);
+    } else if (newTables[i].tag == os2Tag && missingOS2) {
+      (*outputFunc)(outputStream, os2Tab, newTables[i].len);
+    } else if (newTables[i].tag == hheaTag && abbrevHMTX) {
+      (*outputFunc)(outputStream, newHHEATab, newTables[i].len);
+    } else if (newTables[i].tag == hmtxTag && abbrevHMTX) {
+      (*outputFunc)(outputStream, newHMTXTab, newTables[i].len);
     } else if (newTables[i].tag == locaTag && unsortedLoca) {
       for (j = 0; j <= nGlyphs; ++j) {
 	if (locaFmt) {
@@ -1103,6 +1357,8 @@
     }
   }
 
+  gfree(newHMTXTab);
+  gfree(newHHEATab);
   gfree(newCmapTab);
   gfree(newNameTab);
   gfree(tableDir);
@@ -1115,7 +1371,7 @@
 			       FoFiOutputFunc outputFunc,
 			       void *outputStream) {
   char *name;
-  char buf[64];
+  GooString *buf;
   int i;
 
   (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
@@ -1124,15 +1380,17 @@
       if (!(name = encoding[i])) {
 	name = ".notdef";
       }
-      sprintf(buf, "dup %d /", i);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("dup {0:d} /", i);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
       (*outputFunc)(outputStream, name, strlen(name));
       (*outputFunc)(outputStream, " put\n", 5);
     }
   } else {
     for (i = 0; i < 256; ++i) {
-      sprintf(buf, "dup %d /c%02x put\n", i, i);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("dup {0:d} /c{1:02x} put\n", i, i);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
     }
   }
   (*outputFunc)(outputStream, "readonly def\n", 13);
@@ -1143,7 +1401,8 @@
 				  FoFiOutputFunc outputFunc,
 				  void *outputStream) {
   char *name;
-  char buf[64], buf2[16];
+  GooString *buf;
+  char buf2[16];
   int i, k;
 
   // always define '.notdef'
@@ -1178,8 +1437,9 @@
       if (k > 0 && k < nGlyphs) {
 	(*outputFunc)(outputStream, "/", 1);
 	(*outputFunc)(outputStream, name, strlen(name));
-	sprintf(buf, " %d def\n", k);
-	(*outputFunc)(outputStream, buf, strlen(buf));
+	buf = GooString::format(" {0:d} def\n", k);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
       }
     }
   }
@@ -1482,14 +1742,15 @@
 void FoFiTrueType::dumpString(Guchar *s, int length,
 			      FoFiOutputFunc outputFunc,
 			      void *outputStream) {
-  char buf[64];
+  GooString *buf;
   int pad, i, j;
 
   (*outputFunc)(outputStream, "<", 1);
   for (i = 0; i < length; i += 32) {
     for (j = 0; j < 32 && i+j < length; ++j) {
-      sprintf(buf, "%02X", s[i+j] & 0xff);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("{0:02x}", s[i+j] & 0xff);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
     }
     if (i % (65536 - 32) == 65536 - 64) {
       (*outputFunc)(outputStream, ">\n<", 3);
@@ -1536,12 +1797,9 @@
   return checksum;
 }
 
-#define toTag(a,b,c,d) (((unsigned int)(a)<<24) | ((unsigned int)(b)<<16) | ((unsigned int)(c)<<8) | (d))
-
 void FoFiTrueType::parse() {
   Guint topTag;
-  int pos, i, j;
-  unsigned int head;
+  int pos, ver, i, j;
 
   parsedOk = gTrue;
 
@@ -1551,21 +1809,7 @@
     return;
   }
   if (topTag == ttcfTag) {
-    pos = getU32BE(12, &parsedOk);
-    if (!parsedOk) {
-      return;
-    }
-  } else {
-    pos = 0;
-  }
-
-  // read the table directory
-  head = getU32BE(pos, &parsedOk);
-  if (! parsedOk)
-    return;
-  if (head == toTag('t','t','c','f')) {
     /* TTC font */
-    unsigned int tableDir;
     int dircount;
 
     dircount = getU32BE(8, &parsedOk);
@@ -1581,16 +1825,24 @@
     pos = getU32BE(12 + faceIndex * 4, &parsedOk);
     if (! parsedOk)
       return;
+  } else {
+    pos = 0;
   }
 
-  pos += 4;
-  nTables = getU16BE(pos, &parsedOk);
+  // check the sfnt version
+  ver = getU32BE(pos, &parsedOk);
   if (!parsedOk) {
     return;
   }
+  openTypeCFF = ver == 0x4f54544f; // 'OTTO'
 
-  pos += 8;
+  // read the table directory
+  nTables = getU16BE(pos + 4, &parsedOk);
+  if (!parsedOk) {
+    return;
+  }
   tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
+  pos += 12;
   for (i = 0; i < nTables; ++i) {
     tables[i].tag = getU32BE(pos, &parsedOk);
     tables[i].checksum = getU32BE(pos + 4, &parsedOk);
@@ -1610,10 +1862,11 @@
   // the Type 42 spec
   if (seekTable("head") < 0 ||
       seekTable("hhea") < 0 ||
-      seekTable("loca") < 0 ||
       seekTable("maxp") < 0 ||
-      seekTable("glyf") < 0 ||
-      seekTable("hmtx") < 0) {
+      seekTable("hmtx") < 0 ||
+      (!openTypeCFF && seekTable("loca") < 0) ||
+      (!openTypeCFF && seekTable("glyf") < 0) ||
+      (openTypeCFF && seekTable("CFF ") < 0)) {
     parsedOk = gFalse;
     return;
   }
@@ -1662,23 +1915,28 @@
 
   // make sure the loca table is sane (correct length and entries are
   // in bounds)
-  i = seekTable("loca");
-  if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
-    parsedOk = gFalse;
-    return;
-  }
-  for (j = 0; j <= nGlyphs; ++j) {
-    if (locaFmt) {
-      pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
-    } else {
-      pos = getU16BE(tables[i].offset + j*2, &parsedOk);
-    }
-    if (pos < 0 || pos > len) {
+  if (!openTypeCFF) {
+    i = seekTable("loca");
+    if (tables[i].len < 0) {
       parsedOk = gFalse;
+      return;
+    }
+    if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
+      nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1;
+    }
+    for (j = 0; j <= nGlyphs; ++j) {
+      if (locaFmt) {
+	pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
+      } else {
+	pos = getU16BE(tables[i].offset + j*2, &parsedOk);
+      }
+      if (pos < 0 || pos > len) {
+	parsedOk = gFalse;
+      }
+    }
+    if (!parsedOk) {
+      return;
     }
-  }
-  if (!parsedOk) {
-    return;
   }
 
   // read the post table

Index: FoFiTrueType.h
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiTrueType.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- FoFiTrueType.h	2 Feb 2006 22:50:01 -0000	1.3
+++ FoFiTrueType.h	25 Apr 2007 19:59:10 -0000	1.4
@@ -34,9 +34,12 @@
   // Create a FoFiTrueType object from a file on disk.
   static FoFiTrueType *load(char *fileName, int faceIndexA=0);
 
-  FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA=0);
   virtual ~FoFiTrueType();
 
+  // Returns true if this an OpenType font containing CFF data, false
+  // if it's a TrueType font (or OpenType font with TrueType data).
+  GBool isOpenTypeCFF() { return openTypeCFF; }
+
   // Return the number of cmaps defined by this font.
   int getNumCmaps();
 
@@ -58,6 +61,11 @@
   // font does not have a post table.
   int mapNameToGID(char *name);
 
+  // Return the mapping from CIDs to GIDs, and return the number of
+  // CIDs in *<nCIDs>.  This is only useful for CID fonts.  (Only
+  // useful for OpenType CFF fonts.)
+  Gushort *getCIDToGIDMap(int *nCIDs);
+
   // Returns the least restrictive embedding licensing right (as
   // defined by the TrueType spec):
   // * 4: OS/2 table is missing or invalid
@@ -73,38 +81,63 @@
   // <encoding> array specifies the mapping from char codes to names.
   // If <encoding> is NULL, the encoding is unknown or undefined.  The
   // <codeToGID> array specifies the mapping from char codes to GIDs.
+  // (Not useful for OpenType CFF fonts.)
   void convertToType42(char *psName, char **encoding,
 		       Gushort *codeToGID,
 		       FoFiOutputFunc outputFunc, void *outputStream);
 
+  // Convert to a Type 1 font, suitable for embedding in a PostScript
+  // file.  This is only useful with 8-bit fonts.  If <newEncoding> is
+  // not NULL, it will be used in place of the encoding in the Type 1C
+  // font.  If <ascii> is true the eexec section will be hex-encoded,
+  // otherwise it will be left as binary data.  If <psName> is
+  // non-NULL, it will be used as the PostScript font name.  (Only
+  // useful for OpenType CFF fonts.)
+  void convertToType1(char *psName, char **newEncoding, GBool ascii,
+		      FoFiOutputFunc outputFunc, void *outputStream);
+
   // Convert to a Type 2 CIDFont, suitable for embedding in a
   // PostScript file.  <psName> will be used as the PostScript font
   // name (so we don't need to depend on the 'name' table in the
   // font).  The <cidMap> array maps CIDs to GIDs; it has <nCIDs>
-  // entries.
+  // entries.  (Not useful for OpenType CFF fonts.)
   void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs,
 			 GBool needVerticalMetrics,
 			 FoFiOutputFunc outputFunc, void *outputStream);
 
+  // Convert to a Type 0 CIDFont, suitable for embedding in a
+  // PostScript file.  <psName> will be used as the PostScript font
+  // name.  (Only useful for OpenType CFF fonts.)
+  void convertToCIDType0(char *psName,
+			 FoFiOutputFunc outputFunc, void *outputStream);
+
   // Convert to a Type 0 (but non-CID) composite font, suitable for
   // embedding in a PostScript file.  <psName> will be used as the
   // PostScript font name (so we don't need to depend on the 'name'
   // table in the font).  The <cidMap> array maps CIDs to GIDs; it has
-  // <nCIDs> entries.
+  // <nCIDs> entries.  (Not useful for OpenType CFF fonts.)
   void convertToType0(char *psName, Gushort *cidMap, int nCIDs,
 		      GBool needVerticalMetrics,
 		      FoFiOutputFunc outputFunc, void *outputStream);
 
+  // Convert to a Type 0 (but non-CID) composite font, suitable for
+  // embedding in a PostScript file.  <psName> will be used as the
+  // PostScript font name.  (Only useful for OpenType CFF fonts.)
+  void convertToType0(char *psName,
+		      FoFiOutputFunc outputFunc, void *outputStream);
+
   // Write a clean TTF file, filling in missing tables and correcting
   // various other errors.  If <name> is non-NULL, the font is renamed
   // to <name>.  If <codeToGID> is non-NULL, the font is re-encoded,
   // using a Windows Unicode cmap.  If <name> is NULL and the font is
-  // complete and correct, it will be written unmodified.
+  // complete and correct, it will be written unmodified.  (Not useful
+  // for OpenType CFF fonts.)
   void writeTTF(FoFiOutputFunc outputFunc, void *outputStream,
 		char *name = NULL, Gushort *codeToGID = NULL);
 
 private:
 
+  FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA);
   void cvtEncoding(char **encoding,
 		   FoFiOutputFunc outputFunc,
 		   void *outputStream);
@@ -131,6 +164,7 @@
   int locaFmt;
   int bbox[4];
   GooHash *nameToGID;
+  GBool openTypeCFF;
 
   GBool parsedOk;
   int faceIndex;

Index: FoFiType1.cc
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiType1.cc,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- FoFiType1.cc	14 Sep 2005 21:20:36 -0000	1.5
+++ FoFiType1.cc	25 Apr 2007 19:59:10 -0000	1.6
@@ -75,7 +75,7 @@
 void FoFiType1::writeEncoded(char **newEncoding,
 			     FoFiOutputFunc outputFunc, void *outputStream) {
   char buf[512];
-  char *line;
+  char *line, *line2, *p;
   int i;
 
   // copy everything up to the encoding
@@ -101,19 +101,57 @@
   }
   (*outputFunc)(outputStream, "readonly def\n", 13);
   
-  // copy everything after the encoding
+  // find the end of the encoding data
+  //~ this ought to parse PostScript tokens
   if (!strncmp(line, "/Encoding StandardEncoding def", 30)) {
     line = getNextLine(line);
   } else {
-    for (line = getNextLine(line);
-	 line && strncmp(line, "readonly def", 12);
-	 line = getNextLine(line)) ;
-    if (line) {
-      line = getNextLine(line);
+    // skip "/Encoding" + one whitespace char,
+    // then look for 'def' preceded by PostScript whitespace
+    p = line + 10;
+    line = NULL;
+    for (; p < (char *)file + len; ++p) {
+      if ((*p == ' ' || *p == '\t' || *p == '\x0a' ||
+	   *p == '\x0d' || *p == '\x0c' || *p == '\0') &&
+	  p + 4 <= (char *)file + len &&
+	  !strncmp(p + 1, "def", 3)) {
+	line = p + 4;
+	break;
+      }
     }
   }
+
+  // some fonts have two /Encoding entries in their dictionary, so we
+  // check for a second one here
   if (line) {
-    (*outputFunc)(outputStream, line, ((char *)file + len) - line);
+    for (line2 = line, i = 0;
+	 i < 20 && line2 && strncmp(line2, "/Encoding", 9);
+	 line2 = getNextLine(line2), ++i) ;
+    if (i < 20 && line2) {
+      (*outputFunc)(outputStream, line, line2 - line);
+      if (!strncmp(line2, "/Encoding StandardEncoding def", 30)) {
+	line = getNextLine(line2);
+      } else {
+	// skip "/Encoding" + one whitespace char,
+	// then look for 'def' preceded by PostScript whitespace
+	p = line2 + 10;
+	line = NULL;
+	for (; p < (char *)file + len; ++p) {
+	  if ((*p == ' ' || *p == '\t' || *p == '\x0a' ||
+	       *p == '\x0d' || *p == '\x0c' || *p == '\0') &&
+	      p + 4 <= (char *)file + len &&
+	      !strncmp(p + 1, "def", 3)) {
+	    line = p + 4;
+	    break;
+	  }
+	}
+      }
+    }
+
+    // copy everything after the encoding
+    if (line) {
+      (*outputFunc)(outputStream, line, ((char *)file + len) - line);
+    }
   }
 }
 
@@ -178,8 +216,15 @@
 	  if (*p2) {
 	    c = *p2;
 	    *p2 = '\0';
-	    if ((code = atoi(p)) < 256) {
-	      *p2 = c;
+	    code = atoi(p);
+	    *p2 = c;
+	    if (code == 8 && *p2 == '#') {
+	      code = 0;
+	      for (++p2; *p2 >= '0' && *p2 <= '7'; ++p2) {
+		code = code * 8 + (*p2 - '0');
+	      }
+	    }
+	    if (code < 256) {
 	      for (p = p2; *p == ' ' || *p == '\t'; ++p) ;
 	      if (*p == '/') {
 		++p;

Index: FoFiType1C.cc
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiType1C.cc,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- FoFiType1C.cc	14 Sep 2005 21:20:36 -0000	1.3
+++ FoFiType1C.cc	25 Apr 2007 19:59:10 -0000	1.4
@@ -129,24 +129,33 @@
   return map;
 }
 
-void FoFiType1C::convertToType1(char **newEncoding, GBool ascii,
+void FoFiType1C::convertToType1(char *psName, char **newEncoding, GBool ascii,
 				FoFiOutputFunc outputFunc,
 				void *outputStream) {
+  int psNameLen;
   Type1CEexecBuf eb;
   Type1CIndex subrIdx;
   Type1CIndexVal val;
[...965 lines suppressed...]
@@ -949,15 +1070,16 @@
 			       int offset, int nBytes,
 			       Type1CIndex *subrIdx,
 			       Type1CPrivateDict *pDict) {
-  char buf[512];
+  GooString *buf;
   GooString *charBuf;
 
   // generate the charstring
   charBuf = new GooString();
   cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue);
 
-  sprintf(buf, "/%s %d RD ", glyphName, charBuf->getLength());
-  eexecWrite(eb, buf);
+  buf = GooString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength());
+  eexecWrite(eb, buf->getCString());
+  delete buf;
   eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(),
 		       charBuf->getLength());
   eexecWrite(eb, " ND\n");

Index: FoFiType1C.h
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiType1C.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- FoFiType1C.h	2 Feb 2006 22:50:01 -0000	1.3
+++ FoFiType1C.h	25 Apr 2007 19:59:10 -0000	1.4
@@ -138,7 +138,6 @@
   // Create a FoFiType1C object from a file on disk.
   static FoFiType1C *load(char *fileName);
 
-  FoFiType1C(char *fileA, int lenA, GBool freeFileDataA);
   virtual ~FoFiType1C();
 
   // Return the font name.
@@ -156,8 +155,9 @@
   // file.  This is only useful with 8-bit fonts.  If <newEncoding> is
   // not NULL, it will be used in place of the encoding in the Type 1C
   // font.  If <ascii> is true the eexec section will be hex-encoded,
-  // otherwise it will be left as binary data.
-  void convertToType1(char **newEncoding, GBool ascii,
+  // otherwise it will be left as binary data.  If <psName> is non-NULL,
+  // it will be used as the PostScript font name.
+  void convertToType1(char *psName, char **newEncoding, GBool ascii,
 		      FoFiOutputFunc outputFunc, void *outputStream);
 
   // Convert to a Type 0 CIDFont, suitable for embedding in a
@@ -174,6 +174,7 @@
 
 private:
 
+  FoFiType1C(char *fileA, int lenA, GBool freeFileDataA);
   void eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName,
 		     int offset, int nBytes,
 		     Type1CIndex *subrIdx,



More information about the poppler mailing list