summaryrefslogtreecommitdiff
path: root/fofi
diff options
context:
space:
mode:
Diffstat (limited to 'fofi')
-rw-r--r--fofi/FoFiBase.cc12
-rw-r--r--fofi/FoFiIdentifier.cc255
-rw-r--r--fofi/FoFiIdentifier.h11
-rw-r--r--fofi/FoFiTrueType.cc220
-rw-r--r--fofi/FoFiTrueType.h33
-rw-r--r--fofi/FoFiType1C.cc140
-rw-r--r--fofi/Makefile.in4
-rw-r--r--fofi/vms_make.com0
8 files changed, 571 insertions, 104 deletions
diff --git a/fofi/FoFiBase.cc b/fofi/FoFiBase.cc
index 4adef2a..c9ca440 100644
--- a/fofi/FoFiBase.cc
+++ b/fofi/FoFiBase.cc
@@ -84,7 +84,7 @@ int FoFiBase::getU8(int pos, GBool *ok) {
int FoFiBase::getS16BE(int pos, GBool *ok) {
int x;
- if (pos < 0 || pos+1 >= len || pos > INT_MAX - 1) {
+ if (pos < 0 || pos > INT_MAX - 1 || pos+1 >= len) {
*ok = gFalse;
return 0;
}
@@ -99,7 +99,7 @@ int FoFiBase::getS16BE(int pos, GBool *ok) {
int FoFiBase::getU16BE(int pos, GBool *ok) {
int x;
- if (pos < 0 || pos+1 >= len || pos > INT_MAX - 1) {
+ if (pos < 0 || pos > INT_MAX - 1 || pos+1 >= len) {
*ok = gFalse;
return 0;
}
@@ -111,7 +111,7 @@ int FoFiBase::getU16BE(int pos, GBool *ok) {
int FoFiBase::getS32BE(int pos, GBool *ok) {
int x;
- if (pos < 0 || pos+3 >= len || pos > INT_MAX - 3) {
+ if (pos < 0 || pos > INT_MAX - 3 || pos+3 >= len) {
*ok = gFalse;
return 0;
}
@@ -128,7 +128,7 @@ int FoFiBase::getS32BE(int pos, GBool *ok) {
Guint FoFiBase::getU32BE(int pos, GBool *ok) {
Guint x;
- if (pos < 0 || pos+3 >= len || pos > INT_MAX - 3) {
+ if (pos < 0 || pos > INT_MAX - 3 || pos+3 >= len) {
*ok = gFalse;
return 0;
}
@@ -142,7 +142,7 @@ Guint FoFiBase::getU32BE(int pos, GBool *ok) {
Guint FoFiBase::getU32LE(int pos, GBool *ok) {
Guint x;
- if (pos < 0 || pos+3 >= len || pos > INT_MAX - 3) {
+ if (pos < 0 || pos > INT_MAX - 3 || pos+3 >= len) {
*ok = gFalse;
return 0;
}
@@ -157,7 +157,7 @@ Guint FoFiBase::getUVarBE(int pos, int size, GBool *ok) {
Guint x;
int i;
- if (pos < 0 || pos + size > len || pos > INT_MAX - size) {
+ if (pos < 0 || pos > INT_MAX - size || pos + size > len) {
*ok = gFalse;
return 0;
}
diff --git a/fofi/FoFiIdentifier.cc b/fofi/FoFiIdentifier.cc
index 10ac486..978cc70 100644
--- a/fofi/FoFiIdentifier.cc
+++ b/fofi/FoFiIdentifier.cc
@@ -16,6 +16,9 @@
#include <string.h>
#include <limits.h>
#include "gtypes.h"
+#include "gmem.h"
+#include "GString.h"
+#include "GList.h"
#include "FoFiIdentifier.h"
//------------------------------------------------------------------------
@@ -436,12 +439,23 @@ FoFiIdentifierType FoFiIdentifier::identifyMem(char *file, int len) {
FoFiIdentifierType FoFiIdentifier::identifyFile(char *fileName) {
FileReader *reader;
FoFiIdentifierType type;
+ int n;
if (!(reader = FileReader::make(fileName))) {
return fofiIdError;
}
type = identify(reader);
delete reader;
+
+ // Mac OS X dfont files don't have any sort of header or magic number,
+ // so look at the file name extension
+ if (type == fofiIdUnknown) {
+ n = (int)strlen(fileName);
+ if (n >= 6 && !strcmp(fileName + n - 6, ".dfont")) {
+ type = fofiIdDfont;
+ }
+ }
+
return type;
}
@@ -630,3 +644,244 @@ static FoFiIdentifierType identifyCFF(Reader *reader, int start) {
return fofiIdCFF8Bit;
}
}
+
+//------------------------------------------------------------------------
+
+static GList *getTTCFontList(FILE *f);
+static GList *getDfontFontList(FILE *f);
+
+GList *FoFiIdentifier::getFontList(char *fileName) {
+ FILE *f;
+ char buf[4];
+ GList *ret;
+
+ if (!(f = fopen(fileName, "rb"))) {
+ return NULL;
+ }
+ if (fread(buf, 1, 4, f) == 4 &&
+ buf[0] == 0x74 && // 'ttcf'
+ buf[1] == 0x74 &&
+ buf[2] == 0x63 &&
+ buf[3] == 0x66) {
+ ret = getTTCFontList(f);
+ } else {
+ ret = getDfontFontList(f);
+ }
+ fclose(f);
+ return ret;
+}
+
+static GList *getTTCFontList(FILE *f) {
+ Guchar buf[12];
+ Guchar *buf2;
+ int fileLength, nFonts;
+ int tabDirOffset, nTables, nameTabOffset, nNames, stringsOffset;
+ int stringPlatform, stringLength, stringOffset;
+ GBool stringUnicode;
+ int i, j;
+ GList *ret;
+
+ fseek(f, 0, SEEK_END);
+ fileLength = (int)ftell(f);
+ if (fileLength < 0) {
+ goto err1;
+ }
+ fseek(f, 8, SEEK_SET);
+ if (fread(buf, 1, 4, f) != 4) {
+ goto err1;
+ }
+ nFonts = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+ if (nFonts < 0 ||
+ 12 + 4 * nFonts > fileLength) {
+ goto err1;
+ }
+ ret = new GList();
+ for (i = 0; i < nFonts; ++i) {
+ fseek(f, 12 + 4 * i, SEEK_SET);
+ if (fread(buf, 1, 4, f) != 4) {
+ goto err2;
+ }
+ tabDirOffset = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+ if (tabDirOffset < 0 ||
+ tabDirOffset + 12 < 0 ||
+ tabDirOffset + 12 > fileLength) {
+ goto err2;
+ }
+ fseek(f, tabDirOffset, SEEK_SET);
+ if (fread(buf, 1, 12, f) != 12) {
+ goto err2;
+ }
+ nTables = (buf[4] << 8) | buf[5];
+ if (tabDirOffset + 12 + 16 * nTables < 0 ||
+ tabDirOffset + 12 + 16 * nTables > fileLength) {
+ goto err2;
+ }
+ buf2 = (Guchar *)gmallocn(nTables, 16);
+ if ((int)fread(buf2, 1, 16 * nTables, f) != 16 * nTables) {
+ goto err3;
+ }
+ nameTabOffset = 0; // make gcc happy
+ for (j = 0; j < nTables; ++j) {
+ if (buf2[16*j + 0] == 'n' &&
+ buf2[16*j + 1] == 'a' &&
+ buf2[16*j + 2] == 'm' &&
+ buf2[16*j + 3] == 'e') {
+ nameTabOffset = (buf2[16*j + 8] << 24) | (buf2[16*j + 9] << 16) |
+ (buf2[16*j + 10] << 8) | buf2[16*j + 11];
+ break;
+ }
+ }
+ gfree(buf2);
+ if (j >= nTables) {
+ goto err2;
+ }
+ if (nameTabOffset < 0 ||
+ nameTabOffset + 6 < 0 ||
+ nameTabOffset + 6 > fileLength) {
+ goto err2;
+ }
+ fseek(f, nameTabOffset, SEEK_SET);
+ if (fread(buf, 1, 6, f) != 6) {
+ goto err2;
+ }
+ nNames = (buf[2] << 8) | buf[3];
+ stringsOffset = (buf[4] << 8) | buf[5];
+ if (nameTabOffset + 6 + 12 * nNames < 0 ||
+ nameTabOffset + 6 + 12 * nNames > fileLength ||
+ nameTabOffset + stringsOffset < 0) {
+ goto err2;
+ }
+ buf2 = (Guchar *)gmallocn(nNames, 12);
+ if ((int)fread(buf2, 1, 12 * nNames, f) != 12 * nNames) {
+ goto err3;
+ }
+ for (j = 0; j < nNames; ++j) {
+ if (buf2[12*j + 6] == 0 && // 0x0004 = full name
+ buf2[12*j + 7] == 4) {
+ break;
+ }
+ }
+ if (j >= nNames) {
+ goto err3;
+ }
+ stringPlatform = (buf2[12*j] << 8) | buf2[12*j + 1];
+ // stringEncoding = (buf2[12*j + 2] << 8) | buf2[12*j + 3];
+ stringUnicode = stringPlatform == 0 || stringPlatform == 3;
+ stringLength = (buf2[12*j + 8] << 8) | buf2[12*j + 9];
+ stringOffset = nameTabOffset + stringsOffset +
+ ((buf2[12*j + 10] << 8) | buf2[12*j + 11]);
+ gfree(buf2);
+ if (stringOffset < 0 ||
+ stringOffset + stringLength < 0 ||
+ stringOffset + stringLength > fileLength) {
+ goto err2;
+ }
+ buf2 = (Guchar *)gmalloc(stringLength);
+ fseek(f, stringOffset, SEEK_SET);
+ if ((int)fread(buf2, 1, stringLength, f) != stringLength) {
+ goto err3;
+ }
+ if (stringUnicode) {
+ stringLength /= 2;
+ for (j = 0; j < stringLength; ++j) {
+ buf2[j] = buf2[2*j + 1];
+ }
+ }
+ ret->append(new GString((char *)buf2, stringLength));
+ gfree(buf2);
+ }
+ return ret;
+
+ err3:
+ gfree(buf2);
+ err2:
+ deleteGList(ret, GString);
+ err1:
+ return NULL;
+}
+
+static GList *getDfontFontList(FILE *f) {
+ Guchar buf[16];
+ Guchar *resMap;
+ int fileLength, resMapOffset, resMapLength;
+ int resTypeListOffset, resNameListOffset, nTypes;
+ int refListOffset, nFonts, nameOffset, nameLen;
+ int offset, i;
+ GList *ret;
+
+ fseek(f, 0, SEEK_END);
+ fileLength = (int)ftell(f);
+ if (fileLength < 0) {
+ goto err1;
+ }
+ fseek(f, 0, SEEK_SET);
+ if (fread((char *)buf, 1, 16, f) != 16) {
+ goto err1;
+ }
+ resMapOffset = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
+ resMapLength = (buf[12] << 24) | (buf[13] << 16) | (buf[14] << 8) | buf[15];
+ if (resMapOffset < 0 ||
+ resMapOffset >= fileLength ||
+ resMapLength < 0 ||
+ resMapOffset + resMapLength > fileLength ||
+ resMapOffset + resMapLength < 0) {
+ goto err1;
+ }
+ if (resMapLength > 32768) {
+ // sanity check - this probably isn't a dfont file
+ goto err1;
+ }
+ resMap = (Guchar *)gmalloc(resMapLength);
+ fseek(f, resMapOffset, SEEK_SET);
+ if ((int)fread((char *)resMap, 1, resMapLength, f) != resMapLength) {
+ goto err2;
+ }
+ resTypeListOffset = (resMap[24] << 8) | resMap[25];
+ resNameListOffset = (resMap[26] << 8) | resMap[27];
+ nTypes = ((resMap[28] << 8) | resMap[29]) + 1;
+ if (resTypeListOffset + 2 + nTypes * 8 > resMapLength ||
+ resNameListOffset >= resMapLength) {
+ goto err2;
+ }
+ for (i = 0; i < nTypes; ++i) {
+ offset = resTypeListOffset + 2 + 8 * i;
+ if (resMap[offset] == 0x73 && // 'sfnt'
+ resMap[offset+1] == 0x66 &&
+ resMap[offset+2] == 0x6e &&
+ resMap[offset+3] == 0x74) {
+ nFonts = ((resMap[offset+4] << 8) | resMap[offset+5]) + 1;
+ refListOffset = (resMap[offset+6] << 8) | resMap[offset+7];
+ break;
+ }
+ }
+ if (i >= nTypes) {
+ goto err2;
+ }
+ if (resTypeListOffset + refListOffset >= resMapLength ||
+ resTypeListOffset + refListOffset + nFonts * 12 > resMapLength) {
+ goto err2;
+ }
+ ret = new GList();
+ for (i = 0; i < nFonts; ++i) {
+ offset = resTypeListOffset + refListOffset + 12 * i;
+ nameOffset = (resMap[offset+2] << 8) | resMap[offset+3];
+ offset = resNameListOffset + nameOffset;
+ if (offset >= resMapLength) {
+ goto err3;
+ }
+ nameLen = resMap[offset];
+ if (offset + 1 + nameLen > resMapLength) {
+ goto err3;
+ }
+ ret->append(new GString((char *)resMap + offset + 1, nameLen));
+ }
+ gfree(resMap);
+ return ret;
+
+ err3:
+ deleteGList(ret, GString);
+ err2:
+ gfree(resMap);
+ err1:
+ return NULL;
+}
diff --git a/fofi/FoFiIdentifier.h b/fofi/FoFiIdentifier.h
index 79da845..b0307a0 100644
--- a/fofi/FoFiIdentifier.h
+++ b/fofi/FoFiIdentifier.h
@@ -15,6 +15,8 @@
#pragma interface
#endif
+class GList;
+
//------------------------------------------------------------------------
// FoFiIdentifier
//------------------------------------------------------------------------
@@ -28,6 +30,7 @@ enum FoFiIdentifierType {
fofiIdTrueTypeCollection, // TrueType collection
fofiIdOpenTypeCFF8Bit, // OpenType wrapper with 8-bit CFF font
fofiIdOpenTypeCFFCID, // OpenType wrapper with CID CFF font
+ fofiIdDfont, // Mac OS X dfont
fofiIdUnknown, // unknown type
fofiIdError // error in reading the file
};
@@ -35,10 +38,18 @@ enum FoFiIdentifierType {
class FoFiIdentifier {
public:
+ // Identify a font file.
static FoFiIdentifierType identifyMem(char *file, int len);
static FoFiIdentifierType identifyFile(char *fileName);
static FoFiIdentifierType identifyStream(int (*getChar)(void *data),
void *data);
+
+ // Return a list of font names (GString *) in a font collection
+ // file. Indexes into the returned list are indexes into the
+ // collection. This function is only useful with TrueType
+ // collections and Mac dfont files. Returns NULL on error
+ // (including invalid font type).
+ static GList *getFontList(char *fileName);
};
#endif
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;
diff --git a/fofi/FoFiTrueType.h b/fofi/FoFiTrueType.h
index 53d5062..2cf9417 100644
--- a/fofi/FoFiTrueType.h
+++ b/fofi/FoFiTrueType.h
@@ -30,11 +30,19 @@ struct TrueTypeCmap;
class FoFiTrueType: public FoFiBase {
public:
- // Create a FoFiTrueType object from a memory buffer.
- static FoFiTrueType *make(char *fileA, int lenA);
-
- // Create a FoFiTrueType object from a file on disk.
- static FoFiTrueType *load(char *fileName);
+ // Create a FoFiTrueType object from a memory buffer. If
+ // <allowHeadlessCFF> is true, OpenType CFF fonts without the 'head'
+ // table are permitted -- this is useful when calling the convert*
+ // functions.
+ static FoFiTrueType *make(char *fileA, int lenA, int fontNum,
+ GBool allowHeadlessCFF = gFalse);
+
+ // Create a FoFiTrueType object from a file on disk. If
+ // <allowHeadlessCFF> is true, OpenType CFF fonts without the 'head'
+ // table are permitted -- this is useful when calling the convert*
+ // functions.
+ static FoFiTrueType *load(char *fileName, int fontNum,
+ GBool allowHeadlessCFF = gFalse);
virtual ~FoFiTrueType();
@@ -42,6 +50,12 @@ public:
// if it's a TrueType font (or OpenType font with TrueType data).
GBool isOpenTypeCFF() { return openTypeCFF; }
+ // Returns true if this is an OpenType CFF font that is missing the
+ // 'head' table. This is a violation of the OpenType spec, but the
+ // embedded CFF font can be usable for some purposes (e.g., the
+ // convert* functions).
+ GBool isHeadlessCFF() { return headlessCFF; }
+
// Return the number of cmaps defined by this font.
int getNumCmaps();
@@ -148,7 +162,8 @@ public:
private:
- FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA);
+ FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA,
+ int fontNum, GBool isDfont, GBool allowHeadlessCFF);
void cvtEncoding(char **encoding,
FoFiOutputFunc outputFunc,
void *outputStream);
@@ -164,7 +179,9 @@ private:
FoFiOutputFunc outputFunc,
void *outputStream);
Guint computeTableChecksum(Guchar *data, int length);
- void parse();
+ void parse(int fontNum, GBool allowHeadlessCFF);
+ void parseTTC(int fontNum, int *pos);
+ void parseDfont(int fontNum, int *offset, int *pos);
void readPostTable();
int seekTable(const char *tag);
@@ -177,6 +194,8 @@ private:
int bbox[4];
GHash *nameToGID;
GBool openTypeCFF;
+ GBool headlessCFF;
+ GBool isDfont;
GBool parsedOk;
};
diff --git a/fofi/FoFiType1C.cc b/fofi/FoFiType1C.cc
index 93af207..7986cee 100644
--- a/fofi/FoFiType1C.cc
+++ b/fofi/FoFiType1C.cc
@@ -387,24 +387,42 @@ void FoFiType1C::convertToType1(char *psName, const char **newEncoding,
delete buf;
}
if (privateDicts[0].nStemSnapH) {
- eexecWrite(&eb, "/StemSnapH [");
- for (i = 0; i < privateDicts[0].nStemSnapH; ++i) {
- buf = GString::format("{0:s}{1:.4g}",
- i > 0 ? " " : "", privateDicts[0].stemSnapH[i]);
- eexecWrite(&eb, buf->getCString());
- delete buf;
+ // the StemSnapH array should be unique values in ascending order --
+ // if not, just skip it
+ for (i = 1; i < privateDicts[0].nStemSnapH; ++i) {
+ if (privateDicts[0].stemSnapH[i-1] >= privateDicts[0].stemSnapH[i]) {
+ break;
+ }
+ }
+ if (i == privateDicts[0].nStemSnapH) {
+ eexecWrite(&eb, "/StemSnapH [");
+ for (i = 0; i < privateDicts[0].nStemSnapH; ++i) {
+ buf = GString::format("{0:s}{1:.4g}",
+ i > 0 ? " " : "", privateDicts[0].stemSnapH[i]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
}
- eexecWrite(&eb, "] def\n");
}
if (privateDicts[0].nStemSnapV) {
- eexecWrite(&eb, "/StemSnapV [");
- for (i = 0; i < privateDicts[0].nStemSnapV; ++i) {
- buf = GString::format("{0:s}{1:.4g}",
- i > 0 ? " " : "", privateDicts[0].stemSnapV[i]);
- eexecWrite(&eb, buf->getCString());
- delete buf;
+ // the StemSnapV array should be unique values in ascending order --
+ // if not, just skip it
+ for (i = 1; i < privateDicts[0].nStemSnapV; ++i) {
+ if (privateDicts[0].stemSnapV[i-1] >= privateDicts[0].stemSnapV[i]) {
+ break;
+ }
+ }
+ if (i == privateDicts[0].nStemSnapV) {
+ eexecWrite(&eb, "/StemSnapV [");
+ for (i = 0; i < privateDicts[0].nStemSnapV; ++i) {
+ buf = GString::format("{0:s}{1:.4g}",
+ i > 0 ? " " : "", privateDicts[0].stemSnapV[i]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
}
- eexecWrite(&eb, "] def\n");
}
if (privateDicts[0].hasForceBold) {
buf = GString::format("/ForceBold {0:s} def\n",
@@ -719,24 +737,42 @@ void FoFiType1C::convertToCIDType0(char *psName, int *codeMap, int nCodes,
delete buf;
}
if (privateDicts[i].nStemSnapH) {
- (*outputFunc)(outputStream, "/StemSnapH [", 12);
- for (j = 0; j < privateDicts[i].nStemSnapH; ++j) {
- buf = GString::format("{0:s}{1:.4g}",
- j > 0 ? " " : "", privateDicts[i].stemSnapH[j]);
- (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
- delete buf;
+ // the StemSnapH array should be unique values in ascending order --
+ // if not, just skip it
+ for (j = 1; j < privateDicts[i].nStemSnapH; ++j) {
+ if (privateDicts[i].stemSnapH[j-1] >= privateDicts[i].stemSnapH[j]) {
+ break;
+ }
+ }
+ if (j == privateDicts[0].nStemSnapH) {
+ (*outputFunc)(outputStream, "/StemSnapH [", 12);
+ for (j = 0; j < privateDicts[i].nStemSnapH; ++j) {
+ buf = GString::format("{0:s}{1:.4g}",
+ j > 0 ? " " : "", privateDicts[i].stemSnapH[j]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
}
- (*outputFunc)(outputStream, "] def\n", 6);
}
if (privateDicts[i].nStemSnapV) {
- (*outputFunc)(outputStream, "/StemSnapV [", 12);
- for (j = 0; j < privateDicts[i].nStemSnapV; ++j) {
- buf = GString::format("{0:s}{1:.4g}",
- j > 0 ? " " : "", privateDicts[i].stemSnapV[j]);
- (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
- delete buf;
+ // the StemSnapV array should be unique values in ascending order --
+ // if not, just skip it
+ for (j = 1; j < privateDicts[i].nStemSnapV; ++j) {
+ if (privateDicts[i].stemSnapV[j-1] >= privateDicts[i].stemSnapV[j]) {
+ break;
+ }
+ }
+ if (j == privateDicts[0].nStemSnapV) {
+ (*outputFunc)(outputStream, "/StemSnapV [", 12);
+ for (j = 0; j < privateDicts[i].nStemSnapV; ++j) {
+ buf = GString::format("{0:s}{1:.4g}",
+ j > 0 ? " " : "", privateDicts[i].stemSnapV[j]);
+ (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+ delete buf;
+ }
+ (*outputFunc)(outputStream, "] def\n", 6);
}
- (*outputFunc)(outputStream, "] def\n", 6);
}
if (privateDicts[i].hasForceBold) {
buf = GString::format("/ForceBold {0:s} def\n",
@@ -1017,24 +1053,44 @@ void FoFiType1C::convertToType0(char *psName, int *codeMap, int nCodes,
delete buf;
}
if (privateDicts[fd].nStemSnapH) {
- eexecWrite(&eb, "/StemSnapH [");
- for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) {
- buf = GString::format("{0:s}{1:.4g}",
- k > 0 ? " " : "", privateDicts[fd].stemSnapH[k]);
- eexecWrite(&eb, buf->getCString());
- delete buf;
+ // the StemSnapH array should be unique values in ascending order --
+ // if not, just skip it
+ for (k = 1; k < privateDicts[fd].nStemSnapH; ++k) {
+ if (privateDicts[fd].stemSnapH[k-1] >= privateDicts[fd].stemSnapH[k]) {
+ break;
+ }
+ }
+ if (k == privateDicts[0].nStemSnapH) {
+ eexecWrite(&eb, "/StemSnapH [");
+ for (k = 0; k < privateDicts[fd].nStemSnapH; ++k) {
+ buf = GString::format("{0:s}{1:.4g}",
+ k > 0 ? " " : "",
+ privateDicts[fd].stemSnapH[k]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
}
- eexecWrite(&eb, "] def\n");
}
if (privateDicts[fd].nStemSnapV) {
- eexecWrite(&eb, "/StemSnapV [");
- for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) {
- buf = GString::format("{0:s}{1:.4g}",
- k > 0 ? " " : "", privateDicts[fd].stemSnapV[k]);
- eexecWrite(&eb, buf->getCString());
- delete buf;
+ // the StemSnapV array should be unique values in ascending order --
+ // if not, just skip it
+ for (k = 1; k < privateDicts[fd].nStemSnapV; ++k) {
+ if (privateDicts[fd].stemSnapV[k-1] >= privateDicts[fd].stemSnapV[k]) {
+ break;
+ }
+ }
+ if (k == privateDicts[0].nStemSnapV) {
+ eexecWrite(&eb, "/StemSnapV [");
+ for (k = 0; k < privateDicts[fd].nStemSnapV; ++k) {
+ buf = GString::format("{0:s}{1:.4g}",
+ k > 0 ? " " : "",
+ privateDicts[fd].stemSnapV[k]);
+ eexecWrite(&eb, buf->getCString());
+ delete buf;
+ }
+ eexecWrite(&eb, "] def\n");
}
- eexecWrite(&eb, "] def\n");
}
if (privateDicts[fd].hasForceBold) {
buf = GString::format("/ForceBold {0:s} def\n",
diff --git a/fofi/Makefile.in b/fofi/Makefile.in
index f4f5d00..d00f83f 100644
--- a/fofi/Makefile.in
+++ b/fofi/Makefile.in
@@ -14,7 +14,7 @@ VPATH = @srcdir@
GOOSRCDIR = $(srcdir)/../goo
GOOLIBDIR = ../goo
-CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(GOOSRCDIR) -I$(srcdir)
+CXXFLAGS = @CXXFLAGS@ @DEFS@ -I.. -I$(srcdir)/.. -I$(GOOSRCDIR) -I$(srcdir)
CXX = @CXX@
AR = @AR@
@@ -68,4 +68,4 @@ clean:
depend:
$(CXX) $(CXXFLAGS) -MM $(CXX_SRC) >Makefile.dep
-include Makefile.dep
+-include Makefile.dep
diff --git a/fofi/vms_make.com b/fofi/vms_make.com
deleted file mode 100644
index e69de29..0000000
--- a/fofi/vms_make.com
+++ /dev/null