diff options
Diffstat (limited to 'fofi')
-rw-r--r-- | fofi/FoFiBase.cc | 12 | ||||
-rw-r--r-- | fofi/FoFiIdentifier.cc | 255 | ||||
-rw-r--r-- | fofi/FoFiIdentifier.h | 11 | ||||
-rw-r--r-- | fofi/FoFiTrueType.cc | 220 | ||||
-rw-r--r-- | fofi/FoFiTrueType.h | 33 | ||||
-rw-r--r-- | fofi/FoFiType1C.cc | 140 | ||||
-rw-r--r-- | fofi/Makefile.in | 4 | ||||
-rw-r--r-- | fofi/vms_make.com | 0 |
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 |