summaryrefslogtreecommitdiff
path: root/fofi/FoFiTrueType.cc
diff options
context:
space:
mode:
Diffstat (limited to 'fofi/FoFiTrueType.cc')
-rw-r--r--fofi/FoFiTrueType.cc220
1 files changed, 173 insertions, 47 deletions
diff --git a/fofi/FoFiTrueType.cc b/fofi/FoFiTrueType.cc
index 6503fda..8a1bfec 100644
--- a/fofi/FoFiTrueType.cc
+++ b/fofi/FoFiTrueType.cc
@@ -275,10 +275,11 @@ static const char *macGlyphNames[258] = {
// FoFiTrueType
//------------------------------------------------------------------------
-FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) {
+FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA, int fontNum,
+ GBool allowHeadlessCFF) {
FoFiTrueType *ff;
- ff = new FoFiTrueType(fileA, lenA, gFalse);
+ ff = new FoFiTrueType(fileA, lenA, gFalse, fontNum, gFalse, allowHeadlessCFF);
if (!ff->parsedOk) {
delete ff;
return NULL;
@@ -286,15 +287,20 @@ FoFiTrueType *FoFiTrueType::make(char *fileA, int lenA) {
return ff;
}
-FoFiTrueType *FoFiTrueType::load(char *fileName) {
+FoFiTrueType *FoFiTrueType::load(char *fileName, int fontNum,
+ GBool allowHeadlessCFF) {
FoFiTrueType *ff;
char *fileA;
- int lenA;
+ int lenA, n;
+ GBool isDfontA;
if (!(fileA = FoFiBase::readFile(fileName, &lenA))) {
return NULL;
}
- ff = new FoFiTrueType(fileA, lenA, gTrue);
+ n = (int)strlen(fileName);
+ isDfontA = n >= 6 && !strcmp(fileName + n - 6, ".dfont");
+ ff = new FoFiTrueType(fileA, lenA, gTrue, fontNum, isDfontA,
+ allowHeadlessCFF);
if (!ff->parsedOk) {
delete ff;
return NULL;
@@ -302,7 +308,9 @@ FoFiTrueType *FoFiTrueType::load(char *fileName) {
return ff;
}
-FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA):
+FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA,
+ int fontNum, GBool isDfontA,
+ GBool allowHeadlessCFF):
FoFiBase(fileA, lenA, freeFileDataA)
{
tables = NULL;
@@ -310,9 +318,10 @@ FoFiTrueType::FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA):
cmaps = NULL;
nCmaps = 0;
nameToGID = NULL;
+ isDfont = isDfontA;
parsedOk = gFalse;
- parse();
+ parse(fontNum, allowHeadlessCFF);
}
FoFiTrueType::~FoFiTrueType() {
@@ -363,7 +372,26 @@ int FoFiTrueType::mapCodeToGID(int i, int c) {
if (c < 0 || c >= cmaps[i].len - 6) {
return 0;
}
- gid = getU8(cmaps[i].offset + 6 + c, &ok);
+ gid = getU8(pos + 6 + c, &ok);
+ break;
+ case 2:
+ // this only handles single-byte codes
+ if (c < 0 || c > 0xff) {
+ return 0;
+ }
+ // check that: subHeaderKeys[0] = 0
+ // subHeaders[0].firstCode = 0
+ // subHeaders[0].entryCount = 256
+ // subHeaders[0].idDelta = 0
+ if (getU16BE(pos + 6, &ok) != 0 ||
+ getU16BE(pos + 518 + 0, &ok) != 0 ||
+ getU16BE(pos + 518 + 2, &ok) != 256 ||
+ getU16BE(pos + 518 + 4, &ok) != 0) {
+ return 0;
+ }
+ // subHeaders[0].idRangeOffset is a byte offset from itself
+ pos = pos + 518 + 6 + getU16BE(pos + 518 + 6, &ok);
+ gid = getU16BE(pos + 2 * c, &ok);
break;
case 4:
segCnt = getU16BE(pos + 6, &ok) / 2;
@@ -1022,7 +1050,7 @@ void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
if (!missingCmap && !missingName && !missingPost && !missingOS2 &&
!unsortedLoca && !emptyCmap && !badCmapLen && !abbrevHMTX &&
nZeroLengthTables == 0 && nBogusTables == 0 &&
- !name && !codeToGID) {
+ !name && !codeToGID && !isDfont) {
(*outputFunc)(outputStream, (char *)file, len);
goto done1;
}
@@ -1632,6 +1660,14 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
// table, cmpTrueTypeLocaOffset uses offset as its primary sort key,
// and idx as its secondary key (ensuring that adjacent entries with
// the same pos value remain in the same order)
+ //
+ // NB: a glyph description containing 12 zero bytes should be a
+ // valid empty glyph (from my reading of the TrueType spec), but
+ // Acrobat chokes on this (which is an issue when an Xpdf-generated
+ // PS file is converted back to PDF - with Ghostscript or
+ // Distiller), so we drop any glyph descriptions of 12 or fewer
+ // bytes -- an empty glyph description generates an empty glyph with
+ // no errors
locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
i = seekTable("loca");
pos = tables[i].offset;
@@ -1670,11 +1706,11 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
*maxUsedGlyph = -1;
for (i = 0; i <= nGlyphs; ++i) {
locaTable[i].newOffset = pos;
- pos += locaTable[i].len;
- if (pos & 3) {
- pos += 4 - (pos & 3);
- }
- if (locaTable[i].len > 0) {
+ if (locaTable[i].len > 12) {
+ pos += locaTable[i].len;
+ if (pos & 3) {
+ pos += 4 - (pos & 3);
+ }
*maxUsedGlyph = i;
}
}
@@ -1737,14 +1773,17 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
checksum = 0;
glyfPos = tables[seekTable("glyf")].offset;
for (j = 0; j < nGlyphs; ++j) {
- length += locaTable[j].len;
- if (length & 3) {
- length += 4 - (length & 3);
- }
- if (checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
- checksum +=
- computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
- locaTable[j].len);
+ if (locaTable[j].len > 12) {
+ length += locaTable[j].len;
+ if (length & 3) {
+ length += 4 - (length & 3);
+ }
+ if (checkRegion(glyfPos + locaTable[j].origOffset,
+ locaTable[j].len)) {
+ checksum +=
+ computeTableChecksum(file + glyfPos + locaTable[j].origOffset,
+ locaTable[j].len);
+ }
}
}
} else {
@@ -1858,7 +1897,7 @@ void FoFiTrueType::cvtSfnts(FoFiOutputFunc outputFunc,
} else if (i == t42GlyfTable) {
glyfPos = tables[seekTable("glyf")].offset;
for (j = 0; j < nGlyphs; ++j) {
- if (locaTable[j].len > 0 &&
+ if (locaTable[j].len > 12 &&
checkRegion(glyfPos + locaTable[j].origOffset, locaTable[j].len)) {
dumpString(file + glyfPos + locaTable[j].origOffset,
locaTable[j].len, outputFunc, outputStream);
@@ -1950,35 +1989,43 @@ Guint FoFiTrueType::computeTableChecksum(Guchar *data, int length) {
return checksum;
}
-void FoFiTrueType::parse() {
+void FoFiTrueType::parse(int fontNum, GBool allowHeadlessCFF) {
Guint topTag;
- int pos, ver, i, j;
+ int offset, pos, ver, i, j;
parsedOk = gTrue;
- // look for a collection (TTC)
- topTag = getU32BE(0, &parsedOk);
- if (!parsedOk) {
- return;
- }
- if (topTag == ttcfTag) {
- pos = getU32BE(12, &parsedOk);
+ // check for a dfont or TrueType collection (TTC)
+ // offset = start of actual TrueType font file (table positions are
+ // relative to this
+ // pos = position of table directory (relative to offset)
+ if (isDfont) {
+ parseDfont(fontNum, &offset, &pos);
+ } else {
+ offset = 0;
+ topTag = getU32BE(0, &parsedOk);
if (!parsedOk) {
return;
}
- } else {
- pos = 0;
+ if (topTag == ttcfTag) {
+ parseTTC(fontNum, &pos);
+ } else {
+ pos = 0;
+ }
+ }
+ if (!parsedOk) {
+ return;
}
// check the sfnt version
- ver = getU32BE(pos, &parsedOk);
+ ver = getU32BE(offset + pos, &parsedOk);
if (!parsedOk) {
return;
}
openTypeCFF = ver == 0x4f54544f; // 'OTTO'
// read the table directory
- nTables = getU16BE(pos + 4, &parsedOk);
+ nTables = getU16BE(offset + pos + 4, &parsedOk);
if (!parsedOk) {
return;
}
@@ -1986,10 +2033,10 @@ void FoFiTrueType::parse() {
pos += 12;
j = 0;
for (i = 0; i < nTables; ++i) {
- tables[j].tag = getU32BE(pos, &parsedOk);
- tables[j].checksum = getU32BE(pos + 4, &parsedOk);
- tables[j].offset = (int)getU32BE(pos + 8, &parsedOk);
- tables[j].len = (int)getU32BE(pos + 12, &parsedOk);
+ tables[j].tag = getU32BE(offset + pos, &parsedOk);
+ tables[j].checksum = getU32BE(offset + pos + 4, &parsedOk);
+ tables[j].offset = offset + (int)getU32BE(offset + pos + 8, &parsedOk);
+ tables[j].len = (int)getU32BE(offset + pos + 12, &parsedOk);
if (tables[j].offset + tables[j].len >= tables[j].offset &&
tables[j].offset + tables[j].len <= len) {
// ignore any bogus entries in the table directory
@@ -2002,10 +2049,23 @@ void FoFiTrueType::parse() {
return;
}
- // check for tables that are required by both the TrueType spec and
- // the Type 42 spec
- if (seekTable("head") < 0 ||
- seekTable("hhea") < 0 ||
+ // check for the head table; allow for a head-less OpenType CFF font
+ headlessCFF = gFalse;
+ if (seekTable("head") < 0) {
+ if (openTypeCFF && allowHeadlessCFF) {
+ headlessCFF = gTrue;
+ nGlyphs = 0;
+ bbox[0] = bbox[1] = bbox[2] = bbox[3] = 0;
+ locaFmt = 0;
+ return;
+ }
+ parsedOk = gFalse;
+ return;
+ }
+
+ // check for other tables that are required by both the TrueType
+ // spec and the Type 42 spec
+ if (seekTable("hhea") < 0 ||
seekTable("maxp") < 0 ||
seekTable("hmtx") < 0 ||
(!openTypeCFF && seekTable("loca") < 0) ||
@@ -2016,7 +2076,7 @@ void FoFiTrueType::parse() {
}
// read the cmaps
- if ((i = seekTable("cmap")) >= 0) {
+ if ((i = seekTable("cmap")) >= 0 && tables[i].len >= 4) {
pos = tables[i].offset + 2;
nCmaps = getU16BE(pos, &parsedOk);
pos += 2;
@@ -2035,8 +2095,6 @@ void FoFiTrueType::parse() {
if (!parsedOk) {
return;
}
- } else {
- nCmaps = 0;
}
// get the number of glyphs from the maxp table
@@ -2087,6 +2145,74 @@ void FoFiTrueType::parse() {
readPostTable();
}
+// Get the table directory position
+void FoFiTrueType::parseTTC(int fontNum, int *pos) {
+ int nFonts;
+
+ nFonts = getU32BE(8, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (fontNum < 0 || fontNum >= nFonts) {
+ parsedOk = gFalse;
+ return;
+ }
+ *pos = getU32BE(12 + 4 * fontNum, &parsedOk);
+}
+
+void FoFiTrueType::parseDfont(int fontNum, int *offset, int *startPos) {
+ int resMapOffset, resDataOffset;
+ int resTypeListOffset, nTypes, typeTag;
+ int nFonts, refListOffset, dataOffset;
+ int pos, i;
+
+ resDataOffset = getU32BE(0, &parsedOk);
+ resMapOffset = getU32BE(4, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+
+ resTypeListOffset = getU16BE(resMapOffset + 24, &parsedOk);
+ // resNameListOffset = getU16BE(resMapOffset + 26, &parsedOk);
+ nTypes = getU16BE(resMapOffset + 28, &parsedOk) + 1;
+ if (!parsedOk) {
+ return;
+ }
+
+ pos = 0; // make gcc happy
+ for (i = 0; i < nTypes; ++i) {
+ pos = resMapOffset + resTypeListOffset + 2 + 8*i;
+ typeTag = getU32BE(pos, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (typeTag == 0x73666e74) { // 'sfnt'
+ break;
+ }
+ }
+ if (i >= nTypes) {
+ parsedOk = gFalse;
+ return;
+ }
+ nFonts = getU16BE(pos + 4, &parsedOk) + 1;
+ refListOffset = getU16BE(pos + 6, &parsedOk);
+ if (!parsedOk) {
+ return;
+ }
+ if (fontNum < 0 || fontNum >= nFonts) {
+ parsedOk = gFalse;
+ return;
+ }
+ pos = resMapOffset + resTypeListOffset + refListOffset + 12 * fontNum;
+ dataOffset = getU32BE(pos + 4, &parsedOk) & 0x00ffffff;
+ if (!parsedOk) {
+ return;
+ }
+ // the data offset points to a 4-byte length field, which we skip over
+ *offset = resDataOffset + dataOffset + 4;
+ *startPos = 0;
+}
+
void FoFiTrueType::readPostTable() {
GString *name;
int tablePos, postFmt, stringIdx, stringPos;