static fz_error parseTTF(fz_stream *file, int offset, int index, char *path, pdf_xref *xref) { fz_error err = fz_okay; TT_OFFSET_TABLE ttOffsetTable; TT_TABLE_DIRECTORY tblDir; TT_NAME_TABLE_HEADER ttNTHeader; TT_NAME_RECORD ttRecord; char szPSName[MAX_FACENAME] = { 0 }, szTTName[MAX_FACENAME] = { 0 }, szStyle[MAX_FACENAME] = { 0 }; int i, count, tblOffset; fz_seek(file,offset,0); err = safe_read(file, (char *)&ttOffsetTable, sizeof(TT_OFFSET_TABLE)); if (err) return err; // check if this is a TrueType font of version 1.0 or an OpenType font if (BEtoHl(ttOffsetTable.uVersion) != TTC_VERSION1 && ttOffsetTable.uVersion != TTAG_OTTO) return fz_error_make(file->ctx, "fonterror : invalid font version"); // determine the name table's offset by iterating through the offset table count = BEtoHs(ttOffsetTable.uNumOfTables); for (i = 0; i < count; i++) { err = safe_read(file, (char *)&tblDir, sizeof(TT_TABLE_DIRECTORY)); if (err) return err; if (!tblDir.uTag || BEtoHl(tblDir.uTag) == TTAG_name) break; } if (count == i || !tblDir.uTag) return fz_error_make(file->ctx, "fonterror : nameless font"); tblOffset = BEtoHl(tblDir.uOffset); // read the 'name' table for record count and offsets fz_seek(file, tblOffset, 0); err = safe_read(file, (char *)&ttNTHeader, sizeof(TT_NAME_TABLE_HEADER)); if (err) return err; offset = tblOffset + sizeof(TT_NAME_TABLE_HEADER); tblOffset += BEtoHs(ttNTHeader.uStorageOffset); // read through the strings for PostScript name and font family count = BEtoHs(ttNTHeader.uNRCount); for (i = 0; i < count; i++) { short nameId; fz_seek(file, offset + i * sizeof(TT_NAME_RECORD), 0); err = safe_read(file, (char *)&ttRecord, sizeof(TT_NAME_RECORD)); if (err) return err; // ignore non-English strings if (ttRecord.uLanguageID && BEtoHs(ttRecord.uLanguageID) != TT_MS_LANGID_ENGLISH_UNITED_STATES) continue; // ignore names other than font (sub)family and PostScript name nameId = BEtoHs(ttRecord.uNameID); if (TT_NAME_ID_FONT_FAMILY == nameId) err = pdf_read_ttf_string(file, tblOffset, &ttRecord, szTTName, MAX_FACENAME); else if (TT_NAME_ID_FONT_SUBFAMILY == nameId) err = pdf_read_ttf_string(file, tblOffset, &ttRecord, szStyle, MAX_FACENAME); else if (TT_NAME_ID_PS_NAME == nameId) err = pdf_read_ttf_string(file, tblOffset, &ttRecord, szPSName, MAX_FACENAME); if (err) fz_error_handle(file->ctx, err, "ignoring face name decoding fonterror"); } // TODO: is there a better way to distinguish Arial Caps from Arial proper? // cf. http://code.google.com/p/sumatrapdf/issues/detail?id=1290 if (!strcmp(szPSName, "ArialMT") && (strstr(path, "caps") || strstr(path, "Caps"))) return fz_error_make(file->ctx, "ignore %s, as it can't be distinguished from Arial,Regular", path); if (szPSName[0]) { err = insertmapping(xref->ctx, xref->win_fontlist, szPSName, path, index); if (err) return err; } if (szTTName[0]) { // derive a PostScript-like name and add it, if it's different from the font's // included PostScript name; cf. http://code.google.com/p/sumatrapdf/issues/detail?id=376 // append the font's subfamily, unless it's a Regular font if (szStyle[0] && _stricmp(szStyle, "Regular") != 0) { fz_strlcat(szTTName, "-", MAX_FACENAME); fz_strlcat(szTTName, szStyle, MAX_FACENAME); } removespaces(szTTName); // compare the two names before adding this one if (lookupcompare(szTTName, szPSName)) { err = insertmapping(xref->ctx, xref->win_fontlist, szTTName, path, index); if (err) return err; } } return fz_okay; }
static fz_error * parseTTF(fz_stream *file, int offset, int index, char *path) { fz_error *err = nil; int byteread; TT_OFFSET_TABLE ttOffsetTable; TT_TABLE_DIRECTORY tblDir; TT_NAME_TABLE_HEADER ttNTHeader; TT_NAME_RECORD ttRecord; char szTemp[4096]; int found; int i; fz_seek(file,offset,0); SAFE_FZ_READ(file, &ttOffsetTable, sizeof(TT_OFFSET_TABLE)); ttOffsetTable.uNumOfTables = SWAPWORD(ttOffsetTable.uNumOfTables); ttOffsetTable.uMajorVersion = SWAPWORD(ttOffsetTable.uMajorVersion); ttOffsetTable.uMinorVersion = SWAPWORD(ttOffsetTable.uMinorVersion); //check is this is a true type font and the version is 1.0 if(ttOffsetTable.uMajorVersion != 1 || ttOffsetTable.uMinorVersion != 0) return fz_throw("fonterror : invalid font version"); found = 0; for(i = 0; i< ttOffsetTable.uNumOfTables; i++) { SAFE_FZ_READ(file,&tblDir,sizeof(TT_TABLE_DIRECTORY)); memcpy(szTemp, tblDir.szTag, 4); szTemp[4] = 0; if (stricmp(szTemp, "name") == 0) { found = 1; tblDir.uLength = SWAPLONG(tblDir.uLength); tblDir.uOffset = SWAPLONG(tblDir.uOffset); break; } else if (szTemp[0] == 0) { break; } } if (found) { fz_seek(file,tblDir.uOffset,0); SAFE_FZ_READ(file,&ttNTHeader,sizeof(TT_NAME_TABLE_HEADER)); ttNTHeader.uNRCount = SWAPWORD(ttNTHeader.uNRCount); ttNTHeader.uStorageOffset = SWAPWORD(ttNTHeader.uStorageOffset); offset = tblDir.uOffset + sizeof(TT_NAME_TABLE_HEADER); for(i = 0; i < ttNTHeader.uNRCount && err == nil; ++i) { fz_seek(file, offset + sizeof(TT_NAME_RECORD)*i, 0); SAFE_FZ_READ(file,&ttRecord,sizeof(TT_NAME_RECORD)); ttRecord.uNameID = SWAPWORD(ttRecord.uNameID); ttRecord.uLanguageID = SWAPWORD(ttRecord.uLanguageID); // Full Name if(ttRecord.uNameID == 6) { ttRecord.uPlatformID = SWAPWORD(ttRecord.uPlatformID); ttRecord.uEncodingID = SWAPWORD(ttRecord.uEncodingID); ttRecord.uStringLength = SWAPWORD(ttRecord.uStringLength); ttRecord.uStringOffset = SWAPWORD(ttRecord.uStringOffset); fz_seek(file, tblDir.uOffset + ttRecord.uStringOffset + ttNTHeader.uStorageOffset, 0); SAFE_FZ_READ(file, szTemp, ttRecord.uStringLength); switch(ttRecord.uPlatformID) { case PLATFORM_UNICODE: err = decodeunicodeplatform(szTemp, ttRecord.uStringLength, szTemp, sizeof(szTemp), ttRecord.uEncodingID); break; case PLATFORM_MACINTOSH: err = decodemacintoshplatform(szTemp, ttRecord.uStringLength, szTemp, sizeof(szTemp), ttRecord.uEncodingID); break; case PLATFORM_ISO: err = fz_throw("fonterror : unsupported platform"); break; case PLATFORM_MICROSOFT: err = decodemicrosoftplatform(szTemp, ttRecord.uStringLength, szTemp, sizeof(szTemp), ttRecord.uEncodingID); break; } if(err == nil) err = insertmapping(&fontlistMS, szTemp, path, index); } } } cleanup: return err; }