/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (maxpTable == null) { v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, maxp table is invalid or missing"); return(false); } if (v.PerformTest(T.vmtx_TableLength)) { uint CalcTableLength = GetNumOfLongVerMetrics(fontOwner) * 4 + (fontOwner.GetMaxpNumGlyphs() - GetNumOfLongVerMetrics(fontOwner)) * 2; if (CalcTableLength == GetLength()) { v.Pass(T.vmtx_TableLength, P.vmtx_P_TableLength, m_tag); } else { v.Error(T.vmtx_TableLength, E.vmtx_E_TableLength, m_tag); bRet = false; } } return(bRet); }
public new OTFontVal GetFont(uint i) { OTFontVal f = null; Debug.Assert(i < m_nFonts); Debug.Assert(m_FontFileType != FontFileType.INVALID); if (i > 0) { Debug.Assert(m_FontFileType == FontFileType.COLLECTION); } if (i < m_nFonts) { if (m_FontFileType == FontFileType.SINGLE) { f = OTFontVal.ReadFont(this, 0, 0); } else if (m_FontFileType == FontFileType.COLLECTION) { Debug.Assert(m_ttch != null); if (m_ttch != null) { uint nDirOffset = (uint)m_ttch.DirectoryOffsets[(int)i]; f = OTFontVal.ReadFont(this, i, nDirOffset); } } } return(f); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (maxpTable == null) { v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, maxp table is invalid or missing"); return false; } if (v.PerformTest(T.vmtx_TableLength)) { uint CalcTableLength = GetNumOfLongVerMetrics(fontOwner)*4 + (fontOwner.GetMaxpNumGlyphs() - GetNumOfLongVerMetrics(fontOwner))*2; if (CalcTableLength == GetLength()) { v.Pass(T.vmtx_TableLength, P.vmtx_P_TableLength, m_tag); } else { v.Error(T.vmtx_TableLength, E.vmtx_E_TableLength, m_tag); bRet = false; } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.VORG_CFF_Font)) { if (fontOwner.ContainsPostScriptOutlines()) { v.Pass(T.VORG_CFF_Font, P.VORG_P_CFF_Font, m_tag); } else { v.Error(T.VORG_CFF_Font, E.VORG_E_CFF_Font, m_tag); bRet = false; } } if (v.PerformTest(T.VORG_Version)) { if (majorVersion == 1 && minorVersion == 0) { v.Pass(T.VORG_Version, P.VORG_P_Version, m_tag); } else { v.Error(T.VORG_Version, E.VORG_E_Version, m_tag); bRet = false; } } return(bRet); }
/************************ * public static methods */ public static new OTFontVal ReadFont(OTFile file, uint FontFileNumber, uint filepos) { OTFontVal f = null; OffsetTable ot = ReadOffsetTable(file, filepos); if (ot != null) { if (ot.numTables == ot.DirectoryEntries.Count) { OutlineType olt = OutlineType.OUTLINE_INVALID; for (int i = 0; i < ot.DirectoryEntries.Count; i++) { DirectoryEntry temp = (DirectoryEntry)ot.DirectoryEntries[i]; string sTable = (string)temp.tag; if (sTable == "CFF ") { olt = OutlineType.OUTLINE_POSTSCRIPT; break; } else if (sTable == "glyf") { olt = OutlineType.OUTLINE_TRUETYPE; break; } } f = new OTFontVal(file, FontFileNumber, ot, olt); } } return(f); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.VORG_CFF_Font)) { if (fontOwner.ContainsPostScriptOutlines()) { v.Pass(T.VORG_CFF_Font, P.VORG_P_CFF_Font, m_tag); } else { v.Error(T.VORG_CFF_Font, E.VORG_E_CFF_Font, m_tag); bRet = false; } } if (v.PerformTest(T.VORG_Version)) { if (majorVersion == 1 && minorVersion == 0) { v.Pass(T.VORG_Version, P.VORG_P_Version, m_tag); } else { v.Error(T.VORG_Version, E.VORG_E_Version, m_tag); bRet = false; } } return bRet; }
/************************ * public static methods */ public static new OTFontVal ReadFont(OTFile file, uint FontFileNumber, uint filepos) { OTFontVal f = null; OffsetTable ot = ReadOffsetTable(file, filepos); if (ot != null) { if (ot.numTables == ot.DirectoryEntries.Count) { OutlineType olt = OutlineType.OUTLINE_INVALID; for (int i = 0; i<ot.DirectoryEntries.Count; i++) { DirectoryEntry temp = (DirectoryEntry)ot.DirectoryEntries[i]; string sTable = (string)temp.tag; if (sTable == "CFF ") { olt = OutlineType.OUTLINE_POSTSCRIPT; break; } else if (sTable == "glyf") { olt = OutlineType.OUTLINE_TRUETYPE; break; } } f = new OTFontVal(file, FontFileNumber, ot, olt); } } return f; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; v.Info(I.fpgm_I_NotValidated, m_tag); return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; v.Info(I.fpgm_I_NotValidated, m_tag); return(bRet); }
bool Validate_indexSubHeader(Validator v, indexSubHeader iSH, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); if (iSH.indexFormat < 1 || iSH.indexFormat > 5) { string sDetails = "invalid indexFormat: " + sID + ", indexFormat = " + iSH.indexFormat; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } if ((iSH.imageFormat < 1 || iSH.imageFormat > 9 || iSH.imageFormat == 3) && !(version.GetUint() == 0x00030000 && (iSH.imageFormat == 17 || iSH.imageFormat == 18 || iSH.imageFormat == 19) )) { string sDetails = "invalid imageFormat: " + sID + ", imageFormat = " + iSH.imageFormat; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } bool bInconsistentFormats = false; if (iSH.indexFormat == 1 || iSH.indexFormat == 3 || iSH.indexFormat == 4) { if (iSH.imageFormat == 5) { bInconsistentFormats = true; } } else { if (iSH.imageFormat != 5) { bInconsistentFormats = true; } } if (bInconsistentFormats) { string sDetails = "inconsistent formats: " + sID + ", indexFormat = " + iSH.indexFormat + ", imageFormat = " + iSH.imageFormat; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } if (EBDTTable != null) { if (iSH.imageDataOffset > EBDTTable.GetLength()) { string sDetails = "invalid imageDataOffset: " + sID + ", imageDataOffset = " + iSH.imageDataOffset; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } } return(bOk); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; v.Info(T.T_NULL, I.CFF_I_Version, m_tag, major + "." + minor); v.Info(I.CFF_I_NotValidated, m_tag); return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; v.Info(T.T_NULL, I.CFF_I_Version, m_tag, major + "." + minor); v.Info(I.CFF_I_NotValidated, m_tag); return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.vhea_version)) { if (version.GetUint() == 0x00010000 || version.GetUint() == 0x00011000) { v.Pass(T.vhea_version, P.vhea_P_version, m_tag, "0x" + version.GetUint().ToString("x8")); } else { v.Error(T.vhea_version, E.vhea_E_version, m_tag, "0x" + version.GetUint().ToString("x8")); bRet = false; } } if (v.PerformTest(T.vhea_ReservedFields)) { if (reserved1 == 0 && reserved2 == 0 && reserved3 == 0 && reserved4 == 0) { v.Pass(T.vhea_ReservedFields, P.vhea_P_ReservedFields, m_tag); } else { v.Error(T.vhea_ReservedFields, E.vhea_E_ReservedFields, m_tag); bRet = false; } } if (v.PerformTest(T.vhea_metricDataFormat)) { if (metricDataFormat == 0) { v.Pass(T.vhea_metricDataFormat, P.vhea_P_metricDataFormat, m_tag); } else { v.Error(T.vhea_metricDataFormat, E.vhea_E_metricDataFormat, m_tag, metricDataFormat.ToString()); bRet = false; } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.vhea_version)) { if (version.GetUint() == 0x00010000 || version.GetUint() == 0x00011000) { v.Pass(T.vhea_version, P.vhea_P_version, m_tag, "0x" + version.GetUint().ToString("x8")); } else { v.Error(T.vhea_version, E.vhea_E_version, m_tag, "0x" + version.GetUint().ToString("x8")); bRet = false; } } if (v.PerformTest(T.vhea_ReservedFields)) { if (reserved1 == 0 && reserved2 == 0 && reserved3 == 0 && reserved4 == 0) { v.Pass(T.vhea_ReservedFields, P.vhea_P_ReservedFields, m_tag); } else { v.Error(T.vhea_ReservedFields, E.vhea_E_ReservedFields, m_tag); bRet = false; } } if (v.PerformTest(T.vhea_metricDataFormat)) { if (metricDataFormat == 0) { v.Pass(T.vhea_metricDataFormat, P.vhea_P_metricDataFormat, m_tag); } else { v.Error(T.vhea_metricDataFormat, E.vhea_E_metricDataFormat, m_tag, metricDataFormat.ToString()); bRet = false; } } return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.cvt_length)) { if ((m_bufTable.GetLength() & 1) != 0) { v.Error(T.cvt_length, E.cvt_E_length_odd, m_tag); bRet = false; } else { v.Pass(T.cvt_length, P.cvt_P_length_even, m_tag); } } return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.cvt_length)) { if ((m_bufTable.GetLength() & 1) != 0) { v.Error(T.cvt_length, E.cvt_E_length_odd, m_tag); bRet = false; } else { v.Pass(T.cvt_length, P.cvt_P_length_even, m_tag); } } return bRet; }
public bool Validate(Validator validator, OTFontVal fontOwner) { if (validator == null) { return(false); } if (validator.PerformTest(T.loca_Format)) { this.ValidateFormat(validator, fontOwner); } if (validator.PerformTest(T.loca_NumEntries)) { this.ValidateNumEntries(validator, fontOwner); } if (validator.PerformTest(T.loca_OffsetsIncreasing)) { this.ValidateOffsetsIncreasing(validator, fontOwner); } if (validator.PerformTest(T.loca_OffsetWithinGlyfRange)) { this.ValidateOffsetWithinGlyfRange(validator, fontOwner); } if (validator.PerformTest(T.loca_GlyfEntryLengthAlignment)) { this.ValidateGlyfEntryLengthAlignment(validator, fontOwner); } if (validator.PerformTest(T.loca_GlyfEntryEmpty)) { this.ValidateGlyfEntryEmpty(validator, fontOwner); } if (validator.PerformTest(T.loca_GlyfPartiallyUnreferenced)) { this.ValidateGlyfPartiallyUnreferenced(validator, fontOwner); } return(true); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.name_FormatSelector)) { if (FormatSelector == 0) { v.Pass(T.name_FormatSelector, P.name_P_FormatSelector, m_tag); } else { v.Error(T.name_FormatSelector, E.name_E_FormatSelector, m_tag, FormatSelector.ToString()); bRet = false; } } if (v.PerformTest(T.name_StringsWithinTable)) { bool bStringsWithinTable = true; uint tableLength = GetLength(); for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.StringOffset + nr.StringLength > tableLength) { v.Error(T.name_StringsWithinTable, E.name_E_StringsWithinTable, m_tag, "string# " + i); bStringsWithinTable = false; bRet = false; } } else { v.Warning(T.name_StringsWithinTable, W._TEST_W_OtherErrorsInTable, m_tag); bStringsWithinTable = false; break; } } if (bStringsWithinTable) { v.Pass(T.name_StringsWithinTable, P.name_P_StringsWithinTable, m_tag); } } if (v.PerformTest(T.name_NameRecordsSorted)) { bool bSortedOrder = true; if (NumberNameRecords > 1) { NameRecord CurrNR = GetNameRecord(0); NameRecord NextNR = null; for (uint i = 0; i < NumberNameRecords - 1; i++) { NextNR = GetNameRecord(i + 1); if (CurrNR == null || NextNR == null) { bSortedOrder = false; break; } if (CurrNR.PlatformID > NextNR.PlatformID) { bSortedOrder = false; break; } else if (CurrNR.PlatformID == NextNR.PlatformID) { if (CurrNR.EncodingID > NextNR.EncodingID) { bSortedOrder = false; break; } else if (CurrNR.EncodingID == NextNR.EncodingID) { if (CurrNR.LanguageID > NextNR.LanguageID) { bSortedOrder = false; break; } else if (CurrNR.LanguageID == NextNR.LanguageID) { if (CurrNR.NameID > NextNR.NameID) { bSortedOrder = false; break; } } } } CurrNR = NextNR; } } if (bSortedOrder) { v.Pass(T.name_NameRecordsSorted, P.name_P_NameRecordsSorted, m_tag); } else { v.Error(T.name_NameRecordsSorted, E.name_E_NameRecordsSorted, m_tag); bRet = false; } } if (v.PerformTest(T.name_ReservedNameIDs)) { bool bReservedOk = true; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID >= 26 && nr.NameID <= 255) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_ReservedNameIDs, E.name_E_ReservedNameID, m_tag, s); bReservedOk = false; break; } } else { v.Warning(T.name_ReservedNameIDs, W._TEST_W_OtherErrorsInTable, m_tag); bReservedOk = false; break; } } if (bReservedOk) { v.Pass(T.name_ReservedNameIDs, P.name_P_ReservedNameID, m_tag); } } if (v.PerformTest(T.name_BothPlatforms)) { bool bMac = false; bool bMS = false; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 1) { bMac = true; } else if (nr.PlatformID == 3) { bMS = true; } } } if (bMac && bMS) { v.Pass(T.name_BothPlatforms, P.name_P_BothPlatforms, m_tag); } else if (!bMac) { v.Error(T.name_BothPlatforms, E.name_E_NoMacPlatform, m_tag); bRet = false; } else if (!bMS) { v.Error(T.name_BothPlatforms, E.name_E_NoMSPlatform, m_tag); bRet = false; } } if (v.PerformTest(T.name_VersionString)) { bool bFound = false; string sVersion = ""; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 3 && // ms (nr.EncodingID == 1 /* unicode */ || nr.EncodingID == 0 /*symbol*/) && nr.NameID == 5) // version string { bFound = true; bool bVerStringValid = false; byte [] buf = GetEncodedString(nr); string s = ""; if (buf != null) { sVersion = ""; for (int j = 0; j < buf.Length / 2; j++) { char c = (char)(ushort)(buf[j * 2] << 8 | buf[j * 2 + 1]); sVersion += c; } if (sVersion.Length >= 11 && sVersion.StartsWith("Version ") && Char.IsDigit(sVersion, 8)) { int j = 9; // advance past the digits in the major number while (j < sVersion.Length) { if (Char.IsDigit(sVersion, j)) { j++; } else { break; } } // if major number is followed by a period if (sVersion[j] == '.') { // advance past the period j++; // check for a digit if (Char.IsDigit(sVersion, j)) { bVerStringValid = true; } } } } s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", \"" + sVersion + "\""; if (bVerStringValid) { v.Pass(T.name_VersionString, P.name_P_VersionStringFormat, m_tag, s); } else { v.Error(T.name_VersionString, E.name_E_VersionStringFormat, m_tag, s); bRet = false; } // compare to mac version string if present string sMacVer = GetString(1, 0, 0xffff, 5); if (sMacVer != null) { if (sVersion.CompareTo(sMacVer) != 0) { v.Warning(T.name_VersionString, W.name_W_VersionMismatch_MS_MAC, m_tag); } } // compare to 3,10 version string if present string s310Ver = GetString(3, 10, nr.LanguageID, 5); if (s310Ver != null) { if (sVersion.CompareTo(s310Ver) != 0) { string s310 = "platID = 3, encID = 10, langID = " + nr.LanguageID + ", \"" + s310Ver + "\""; v.Warning(T.name_VersionString, W.name_W_VersionMismatch_3_1_3_10, m_tag, s + " / " + s310); } } } } } if (!bFound) { v.Error(T.name_VersionString, E.name_E_VersionStringNotFound, m_tag); bRet = false; } } if (v.PerformTest(T.name_PlatformSpecificEncoding)) { bool bIDsOk = true; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 0) // unicode { if (nr.EncodingID > 7) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s); bIDsOk = false; bRet = false; } } else if (nr.PlatformID == 1) // mac { if (nr.EncodingID > 32) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s); bIDsOk = false; bRet = false; } } else if (nr.PlatformID == 2) // iso { if (nr.EncodingID > 2) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s); bIDsOk = false; bRet = false; } } else if (nr.PlatformID == 3) // MS { if (nr.EncodingID > 10) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s); bIDsOk = false; bRet = false; } } /* * else if (nr.PlatformID == 4) // Custom * { * } */ } else { v.Warning(T.name_PlatformSpecificEncoding, W._TEST_W_OtherErrorsInTable, m_tag); bIDsOk = false; break; } } if (bIDsOk) { v.Pass(T.name_PlatformSpecificEncoding, P.name_P_PlatformSpecificEncoding, m_tag); } } if (v.PerformTest(T.name_MSLanguageIDs)) { bool bFound = false; bool bIDsOk = true; ushort [] MSLangIDs = // taken from Q224804 { 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040D, 0x040e, 0x040F, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041D, 0x041E, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0429, 0x042a, 0x042b, 0x042c, 0x042D, 0x042e, 0x042f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043b, 0x043d, 0x043e, 0x043f, 0x0441, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0457, 0x0459, 0x0461, 0x0801, 0x0804, 0x0807, 0x0809, 0x080a, 0x080c, 0x0810, 0x0812, 0x0813, 0x0814, 0x0816, 0x0818, 0x0819, 0x081a, 0x081d, 0x0820, 0x0827, 0x082c, 0x083e, 0x0843, 0x0860, 0x0861, 0x0C01, 0x0C04, 0x0c07, 0x0c09, 0x0c0a, 0x0c0c, 0x0c1a, 0x1001, 0x1004, 0x1007, 0x1009, 0x100a, 0x100c, 0x1401, 0x1404, 0x1407, 0x1409, 0x140a, 0x140c, 0x1801, 0x1809, 0x180a, 0x180c, 0x1C01, 0x1c09, 0x1c0a, 0x2001, 0x2009, 0x200a, 0x2401, 0x2409, 0x240a, 0x2801, 0x2809, 0x280a, 0x2C01, 0x2c09, 0x2c0a, 0x3001, 0x3009, 0x300a, 0x3401, 0x3409, 0x340a, 0x3801, 0x380a, 0x3C01, 0x3c0a, 0x4001, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a }; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 3 && nr.EncodingID == 1) { bFound = true; bool bValidID = false; for (uint j = 0; j < MSLangIDs.Length; j++) { if (nr.LanguageID == MSLangIDs[j]) { bValidID = true; break; } } if (!bValidID) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = 0x" + nr.LanguageID.ToString("x4") + ", nameID = " + nr.NameID; v.Error(T.name_MSLanguageIDs, E.name_E_MSLanguageID, m_tag, s); bIDsOk = false; bRet = false; } } } } if (bFound && bIDsOk) { v.Pass(T.name_MSLanguageIDs, P.name_P_MSLanguageID, m_tag); } } if (v.PerformTest(T.name_unicode_length)) { bool bLengthsOk = true; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 0 || nr.PlatformID == 2 || // unicode or iso platform (nr.PlatformID == 3 && nr.EncodingID == 1)) // microsoft platform, unicode encoding { if ((nr.StringLength & 1) == 1) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID + ", length = " + nr.StringLength; v.Error(T.name_unicode_length, E.name_E_UnicodeLength, m_tag, s); bLengthsOk = false; bRet = false; } } } else { v.Warning(T.name_unicode_length, W._TEST_W_OtherErrorsInTable, m_tag); bLengthsOk = false; break; } } if (bLengthsOk) { v.Pass(T.name_unicode_length, P.name_P_UnicodeLength, m_tag); } } if (v.PerformTest(T.name_Postscript)) { bool bPostscriptOk = true; string sPostscriptMac = GetString(1, 0, 0, 6); if (sPostscriptMac != null) { if (sPostscriptMac.Length > 63) { v.Error(T.name_Postscript, E.name_E_Postscript_length, m_tag, "name string (1, 0, 0, 6) is " + sPostscriptMac.Length + " characters long"); bRet = false; bPostscriptOk = false; } for (int i = 0; i < sPostscriptMac.Length; i++) { char c = sPostscriptMac[i]; if (c < 33 || c > 126 || c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '<' || c == '>' || c == '/' || c == '%') { v.Error(T.name_Postscript, E.name_E_Postscript_chars, m_tag, "name string (1, 0, 0, 6) contains an illegal character at index " + i); bRet = false; bPostscriptOk = false; } } } ushort nEncoding = 1; if (fontOwner.ContainsMsSymbolEncodedCmap()) { nEncoding = 0; } string sPostscriptMS = GetString(3, nEncoding, 0x409, 6); // ms if (sPostscriptMS != null) { if (sPostscriptMS.Length > 63) { v.Error(T.name_Postscript, E.name_E_Postscript_length, m_tag, "name string (3, " + nEncoding + ", 0x409, 6) is " + sPostscriptMS.Length + " characters long"); bRet = false; bPostscriptOk = false; } for (int i = 0; i < sPostscriptMS.Length; i++) { char c = sPostscriptMS[i]; if (c < 33 || c > 126 || c == '[' || c == ']' || c == '(' || c == ')' || c == '{' || c == '}' || c == '<' || c == '>' || c == '/' || c == '%') { v.Error(T.name_Postscript, E.name_E_Postscript_chars, m_tag, "name string (3, " + nEncoding + ", 0x409, 6) contains an illegal character at index " + i); bRet = false; bPostscriptOk = false; } } } if (sPostscriptMac == null && sPostscriptMS != null) { v.Error(T.name_Postscript, E.name_E_Postscript_missing, m_tag, "Mac Postscript string is missing, but MS Postscript string is present"); bRet = false; bPostscriptOk = false; } else if (sPostscriptMac != null && sPostscriptMS == null) { v.Error(T.name_Postscript, E.name_E_Postscript_missing, m_tag, "MS Postscript string is missing, but Mac Postscript string is present"); bRet = false; bPostscriptOk = false; } if (sPostscriptMac != null && sPostscriptMS != null) { if (sPostscriptMac != sPostscriptMS) { v.Error(T.name_Postscript, E.name_E_Postscript_unequal, m_tag, "mac postscript = " + sPostscriptMac + ", MS postscript = " + sPostscriptMS); bRet = false; bPostscriptOk = false; } } if (sPostscriptMac != null && sPostscriptMS != null && bPostscriptOk) { v.Pass(T.name_Postscript, P.name_P_Postscript, m_tag); } } if (v.PerformTest(T.name_Subfamily)) { string sStyle = GetStyleString(); if (sStyle != null) { Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2"); if (OS2Table != null) { bool bStyleOk = true; string sStyleDetails = ""; string s = sStyle.ToLower(); bool bItalic = ((OS2Table.fsSelection & 0x01) != 0); bool bBold = ((OS2Table.fsSelection & 0x20) != 0); if (bItalic) { if (s.IndexOf("italic") == -1 && s.IndexOf("oblique") == -1) { bStyleOk = false; sStyleDetails = "OS/2.fsSelection italic bit is set, but subfamily string = '" + sStyle + "'"; } } else { if (s.IndexOf("italic") != -1 || s.IndexOf("oblique") != -1) { bStyleOk = false; sStyleDetails = "OS/2.fsSelection italic bit is clear, but subfamily string = '" + sStyle + "'"; } } if (bBold) { if (s.IndexOf("bold") == -1) { bStyleOk = false; sStyleDetails = "OS/2.fsSelection bold bit is set, but subfamily string = '" + sStyle + "'"; } } else { if (s.IndexOf("bold") != -1) { bStyleOk = false; sStyleDetails = "OS/2.fsSelection bold bit is clear, but subfamily string = '" + sStyle + "'"; } } if (bStyleOk) { v.Pass(T.name_Subfamily, P.name_P_subfamily, m_tag); } else { v.Warning(T.name_Subfamily, W.name_W_subfamily_style, m_tag, sStyleDetails); } } } } if (v.PerformTest(T.name_NoFormat14)) { bool bStringOK = true; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null && nr.NameID == 19 && nr.PlatformID == 0 && nr.EncodingID == 5) { string sDetails = "name string(" + nr.PlatformID + ", " + nr.EncodingID + ", 0x" + nr.LanguageID.ToString("x4") + ", " + nr.NameID + ", offset=0x" + nr.StringOffset.ToString("x4") + ")"; v.Error(T.name_NoFormat14, E.name_E_NoFormat14, m_tag, sDetails); bRet = false; bStringOK = false; } } if (bStringOK) { string sDetails = "PlatformID=0, EncodingID=5 is for " + "Variation Sequences (Format 14)"; v.Pass(T.name_NoFormat14, P.name_P_NoFormat14, m_tag, sDetails); } } if (v.PerformTest(T.name_SampleString)) { Table_cmap cmapTable = (Table_cmap)fontOwner.GetTable("cmap"); if (cmapTable != null) { for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID == 19) { if (nr.PlatformID == 0 && nr.EncodingID == 5) { // Unicode platform encoding ID 5 can be // used for encodings in the 'cmap' table // but not for strings in the 'name' table. // It has already been flagged as an error, // so we will just skip it here. break; } Table_cmap.Subtable CmapSubTable = cmapTable.GetSubtable(nr.PlatformID, nr.EncodingID); if (CmapSubTable != null) { bool bStringOk = true; byte[] strbuf = GetEncodedString(nr); for (uint j = 0; j < strbuf.Length;) { if (CmapSubTable.MapCharToGlyph(strbuf, j, true) == 0) { string sDetails = "name string(" + nr.PlatformID + ", " + nr.EncodingID + ", 0x" + nr.LanguageID.ToString("x4") + ", " + nr.NameID + "), character at index " + j + " is not mapped"; v.Error(T.name_SampleString, E.name_E_sample, m_tag, sDetails); bStringOk = false; bRet = false; break; } j += CmapSubTable.BytesInChar(strbuf, j); } if (bStringOk) { string sDetails = "name string(" + nr.PlatformID + ", " + nr.EncodingID + ", 0x" + nr.LanguageID.ToString("x4") + ", " + nr.NameID + ")"; v.Pass(T.name_SampleString, P.name_P_sample, m_tag, sDetails); } } } } } } } if (v.PerformTest(T.name_NameID1to6)) { for (uint id = 1; id <= 6; id++) { bool bFound = false; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID == id) { bFound = true; break; } } } if (!bFound) { v.Warning(T.name_NameID1to6, W.name_W_ID_1to6_Required_For_Common_OSes, m_tag, "Missing Name ID " + id); } } } if (v.PerformTest(T.name_PreferredFamily)) { bool bFound = false; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID == 16) { string sPrefFam = this.GetString(nr.PlatformID, nr.EncodingID, nr.LanguageID, 16); string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID + ", \"" + sPrefFam + "\""; v.Info(T.name_PreferredFamily, I.name_I_Preferred_family_present, m_tag, s); bFound = true; } } } if (!bFound) { v.Info(T.name_PreferredFamily, I.name_I_Preferred_family_not_present, m_tag); } } if (v.PerformTest(T.name_PreferredSubfamily)) { bool bFound = false; for (uint i = 0; i < NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID == 17) { string sPrefSubfam = this.GetString(nr.PlatformID, nr.EncodingID, nr.LanguageID, 17); string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID + ", \"" + sPrefSubfam + "\""; v.Info(T.name_PreferredSubfamily, I.name_I_Preferred_subfamily_present, m_tag, s); bFound = true; } } } if (!bFound) { v.Info(T.name_PreferredSubfamily, I.name_I_Preferred_subfamily_not_present, m_tag); } } if (v.PerformTest(T.name_CopyrightConsistent)) { bool bCopyrightOk = true; // get mac roman English Copyright string if present string sMac = GetString(1, 0, 0, 0); // get windows 3,0 English Copyright string if present string sWin3_0 = GetString(3, 0, 1033, 0); // get windows 3,1 English Copyright string if present string sWin3_1 = GetString(3, 1, 1033, 0); // get windows 3,10 English Copyright string if present string sWin3_10 = GetString(3, 10, 1033, 0); // compare strings if (sMac != null) { if (sWin3_0 != null) { if (sWin3_0.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,0)='" + sMac + "', (3,0,1033,0)='" + sWin3_0 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } if (sWin3_1 != null) { if (sWin3_1.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,0)='" + sMac + "', (3,1,1033,0)='" + sWin3_1 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,0)='" + sMac + "', (3,10,1033,0)='" + sWin3_10 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } } if (sWin3_0 != null) { if (sWin3_1 != null) { if (sWin3_1.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,0)='" + sWin3_0 + "', (3,1,1033,0)='" + sWin3_1 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,0)='" + sWin3_0 + "', (3,10,1033,0)='" + sWin3_10 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } } if (sWin3_1 != null) { if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_1) != 0) { string sDetails = "(3,1,1033,0)='" + sWin3_1 + "', (3,10,1033,0)='" + sWin3_10 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } } if (bCopyrightOk) { v.Pass(T.name_CopyrightConsistent, P.name_P_CopyrightConsistent, m_tag); } else { //bRet = false; } } if (v.PerformTest(T.name_TrademarkConsistent)) { bool bTrademarkOk = true; // get mac roman English Trademark string if present string sMac = GetString(1, 0, 0, 7); // get windows 3,0 English Trademark string if present string sWin3_0 = GetString(3, 0, 1033, 7); // get windows 3,1 English Trademark string if present string sWin3_1 = GetString(3, 1, 1033, 7); // get windows 3,10 English Trademark string if present string sWin3_10 = GetString(3, 10, 1033, 7); // compare strings if (sMac != null) { if (sWin3_0 != null) { if (sWin3_0.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,7)='" + sMac + "', (3,0,1033,7)='" + sWin3_0 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } if (sWin3_1 != null) { if (sWin3_1.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,7)='" + sMac + "', (3,1,1033,7)='" + sWin3_1 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,7)='" + sMac + "', (3,10,1033,7)='" + sWin3_10 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } } if (sWin3_0 != null) { if (sWin3_1 != null) { if (sWin3_1.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,7)='" + sWin3_0 + "', (3,1,1033,7)='" + sWin3_1 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,7)='" + sWin3_0 + "', (3,10,1033,7)='" + sWin3_10 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } } if (sWin3_1 != null) { if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_1) != 0) { string sDetails = "(3,1,1033,7)='" + sWin3_1 + "', (3,10,1033,7)='" + sWin3_10 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } } if (bTrademarkOk) { v.Pass(T.name_TrademarkConsistent, P.name_P_TrademarkConsistent, m_tag); } else { //bRet = false; } } if (v.PerformTest(T.name_DescriptionConsistent)) { bool bDescriptionOk = true; // get mac roman English Description string if present string sMac = GetString(1, 0, 0, 10); // get windows 3,0 English Description string if present string sWin3_0 = GetString(3, 0, 1033, 10); // get windows 3,1 English Description string if present string sWin3_1 = GetString(3, 1, 1033, 10); // get windows 3,10 English Description string if present string sWin3_10 = GetString(3, 10, 1033, 10); // compare strings if (sMac != null) { if (sWin3_0 != null) { if (sWin3_0.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,10)='" + sMac + "', (3,0,1033,10)='" + sWin3_0 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } if (sWin3_1 != null) { if (sWin3_1.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,10)='" + sMac + "', (3,1,1033,10)='" + sWin3_1 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,10)='" + sMac + "', (3,10,1033,10)='" + sWin3_10 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } } if (sWin3_0 != null) { if (sWin3_1 != null) { if (sWin3_1.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,10)='" + sWin3_0 + "', (3,1,1033,10)='" + sWin3_1 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,10)='" + sWin3_0 + "', (3,10,1033,10)='" + sWin3_10 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } } if (sWin3_1 != null) { if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_1) != 0) { string sDetails = "(3,1,1033,10)='" + sWin3_1 + "', (3,10,1033,10)='" + sWin3_10 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } } if (bDescriptionOk) { v.Pass(T.name_DescriptionConsistent, P.name_P_DescriptionConsistent, m_tag); } else { //bRet = false; } } return(bRet); }
bool Validate_indexSubTable_format2(Validator v, indexSubTable2 ist2, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); // header has already been validated // validate the image size uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1; if (nGlyphsInRange*ist2.imageSize > EBDTTable.GetLength()) { string sDetails = "images extend past end of EBDT table: " + sID + ", imageSize = " + ist2.imageSize + ", EBDT length = " + EBDTTable.GetLength(); v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // validate the bigGlyphMetrics val_EBDT.bigGlyphMetrics_val bgm = val_EBDT.bigGlyphMetrics_val.CreateFromBigGlyphMetrics(ist2.bigMetrics); bgm.Validate(v, sID, this); return bOk; }
bool Validate_indexSubTable_format3(Validator v, indexSubTable3 ist3, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); // header has already been validated // validate the array of offsets int nArrSize = ista.lastGlyphIndex - ista.firstGlyphIndex + 1; uint nEBDTLength = EBDTTable.GetLength(); for (ushort i=0; i<nArrSize; i++) { uint offsetImage = ist3.GetOffset(i) + ist3.header.imageDataOffset; if (offsetImage > nEBDTLength) { string sDetails = "invalid offset: " + sID + ", offset[" + i + "] = " + offsetImage + ", EBDT length = " + nEBDTLength; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } } return bOk; }
/***************** * protected methods */ /***************** * public methods */ //meant to avoid code repetition (is called from OTFontVal too) public bool ValidateTable(OTTable table, Validator v, DirectoryEntry de, OTFontVal fontOwner) { String tname = GetTableManager().GetUnaliasedTableName(de.tag); bool bRet = true; // verify the checksum value from the directory entry matches the checksum for the table if (!(tname == "DSIG" && IsCollection())) { uint calcChecksum = 0; if (table != null) { calcChecksum = table.CalcChecksum(); } if (de.checkSum != calcChecksum) { string s = "table '" + de.tag + "', calc: 0x" + calcChecksum.ToString("x8") + ", font: 0x" + de.checkSum.ToString("x8"); v.Error(T.T_NULL, E._DE_E_ChecksumError, de.tag, s); bRet = false; } } // verify that table has pad bytes set to zero if (table != null) { uint nBytes = GetNumPadBytesAfterTable(table); bool bPadBytesZero = true; if (nBytes != 0) { long PadFilePos = table.GetBuffer().GetFilePos() + table.GetBuffer().GetLength(); byte[] padbuf = ReadBytes(PadFilePos, nBytes); for (int iByte = 0; iByte < padbuf.Length; iByte++) { if (padbuf[iByte] != 0) { bPadBytesZero = false; break; } } } if (bPadBytesZero == false) { v.Warning(T.T_NULL, W._DE_W_PadBytesNotZero, de.tag, "after " + de.tag + " table"); } } // ask the table object to validate its data if (!(tname == "DSIG" && IsCollection())) v.OnTableValidationEvent(de, true); if (table != null) { if (v.TestTable(de.tag)) // don't test deselected tables { try { ITableValidate valtable = (ITableValidate)table; bRet &= valtable.Validate(v, fontOwner); } catch (InvalidCastException e) { v.ApplicationError(T.T_NULL, E._Table_E_Exception, table.m_tag, e.ToString()); bRet = false; } } else { v.Info(I._Table_I_NotSelected, de.tag); } } else { if (de.length == 0) { // check if it's a known OT table type since zero length private tables seem allowable if (TableManager.IsKnownOTTableType(de.tag)) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry length is zero"); bRet = false; } } else if (de.offset == 0) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry offset is zero"); bRet = false; } else if (de.offset > GetFileLength()) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table offset points past end of file"); bRet = false; } else if (de.offset + de.length > GetFileLength()) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table extends past end of file"); bRet = false; } else { v.Error(E._Table_E_Invalid, de.tag); bRet = false; } } if (!(tname == "DSIG" && IsCollection())) v.OnTableValidationEvent(de, false); return bRet; }
public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.cmap_Version)) { if (TableVersionNumber == 0) { v.Pass(T.cmap_Version, P.cmap_P_version, m_tag); } else { v.Error(T.cmap_Version, E.cmap_E_version, m_tag, TableVersionNumber.ToString()); bRet = false; } } // Check that the number of encoding records seems to // agree with the numTables field, and that each offset // is greater than 0 and less than the length of the cmap // table. bool bOffsetsOk = true; if (v.PerformTest(T.cmap_SubtableOffset)) { for (uint i=0; i<NumberOfEncodingTables; i++) { EncodingTableEntry ete = GetEncodingTableEntry(i); if (ete != null) { if (ete.offset == 0) { v.Error(T.cmap_SubtableOffset, E.cmap_E_SubtableOffset_zero, m_tag, "encoding table entry index = " + i.ToString() + ", platformID = " + ete.platformID + ", encodingID = " + ete.encodingID); bRet = false; bOffsetsOk = false; } if (ete.offset > m_bufTable.GetLength()) { v.Error(T.cmap_SubtableOffset, E.cmap_E_SubtableOffset_eot, m_tag, "encoding table entry index = " + i.ToString() + ", platformID = " + ete.platformID + ", encodingID = " + ete.encodingID); bRet = false; bOffsetsOk = false; } } else { v.Warning(T.cmap_SubtableOffset, W._TEST_W_OtherErrorsInTable, m_tag, "cmap table appears to be corrupt. " + " No further tests will be performed."); return bRet; } } if (bOffsetsOk) { v.Pass(T.cmap_SubtableOffset, P.cmap_P_SubtableOffset, m_tag); } } // Check that each subtable can be retrieved from the font // and that its offset + length lies within the cmap. bool bLengthsOk = true; if (v.PerformTest(T.cmap_SubtableLength)) { for (uint i=0; i<NumberOfEncodingTables; i++) { EncodingTableEntry ete = GetEncodingTableEntry(i); Subtable st = GetSubtable(ete); if (st != null) { if (st.length == 0) { v.Error(T.cmap_SubtableLength, E.cmap_E_SubtableLength_zero, m_tag, i.ToString()); bRet = false; bLengthsOk = false; } if (ete.offset + st.length > m_bufTable.GetLength()) { v.Error(T.cmap_SubtableLength, E.cmap_E_SubtableLength_eot, m_tag, i.ToString()); bRet = false; bLengthsOk = false; } } else { string sDetails = "PlatID = " + ete.platformID + ", EncID = " + ete.encodingID; v.Warning(T.cmap_SubtableLength, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate the length of subtable - " + sDetails); bLengthsOk = false; } } if (bLengthsOk) { v.Pass(T.cmap_SubtableLength, P.cmap_P_SubtableLength, m_tag); } } // Assuming previous tests ok, check that sort order is by // 1. increasing platformID // 2. increasing encodingID // 3. increasing language if (v.PerformTest(T.cmap_SubtableSortOrder)) { if (bOffsetsOk && bLengthsOk) { bool bOrderOk = true; if (NumberOfEncodingTables > 1) { EncodingTableEntry etePrev = GetEncodingTableEntry(0); for (uint i=1; i<NumberOfEncodingTables; i++) { EncodingTableEntry ete = GetEncodingTableEntry(i); if (etePrev.platformID == ete.platformID) { if (etePrev.encodingID == ete.encodingID) { Subtable stPrev = GetSubtable(etePrev); Subtable st = GetSubtable(ete); if (stPrev.language > st.language) { bOrderOk = false; } } else if (etePrev.encodingID > ete.encodingID) { bOrderOk = false; } } else if (etePrev.platformID > ete.platformID) { bOrderOk = false; } etePrev = ete; } } if (bOrderOk) { v.Pass(T.cmap_SubtableSortOrder, P.cmap_P_SubtableSortOrder, m_tag); } else { v.Error(T.cmap_SubtableSortOrder, E.cmap_E_SubtableSortOrder, m_tag); bRet = false; } } else { v.Warning(T.cmap_SubtableSortOrder, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate sort order"); } } // Check that no encoding record has the same // (platformID,encodingID,language) // as the previous one. if (v.PerformTest(T.cmap_DuplicateSubtables)) { if (bOffsetsOk && bLengthsOk) { bool bNoDuplicates = true; if (NumberOfEncodingTables > 1) { EncodingTableEntry etePrev = GetEncodingTableEntry(0); for (uint i=1; i<NumberOfEncodingTables; i++) { EncodingTableEntry ete = GetEncodingTableEntry(i); if (etePrev.platformID == ete.platformID) { if (etePrev.encodingID == ete.encodingID) { Subtable stPrev = GetSubtable(etePrev); Subtable st = GetSubtable(ete); if (stPrev.language == st.language) { bNoDuplicates = false; } } } etePrev = ete; } } if (bNoDuplicates) { v.Pass(T.cmap_DuplicateSubtables, P.cmap_P_DuplicateSubtables, m_tag); } else { v.Error(T.cmap_DuplicateSubtables, E.cmap_E_DuplicateSubtables, m_tag); bRet = false; } } else { string unable = "unable to validate that there are " + "no duplicate subtables"; v.Warning(T.cmap_DuplicateSubtables, W._TEST_W_OtherErrorsInTable, m_tag, unable ); } } // Check that no subtable overlaps and subtable following it, // in other words, check for the beginning of one subtable // falling within the bounds of a subtable that follows it. if (v.PerformTest(T.cmap_SubtableOverlap)) { if (bOffsetsOk && bLengthsOk) { bool bNoOverlap = true; if (NumberOfEncodingTables > 1) { for (uint i=0; i<NumberOfEncodingTables; i++) { EncodingTableEntry ete1 = GetEncodingTableEntry(i); Subtable st1 = GetSubtable(ete1); for (uint j=i+1; j<NumberOfEncodingTables; j++) { EncodingTableEntry ete2 = GetEncodingTableEntry(j); Subtable st2 = GetSubtable(ete2); if ( (ete1.offset > ete2.offset && ete1.offset < ete2.offset + st2.length) || (ete2.offset > ete1.offset && ete2.offset < ete1.offset + st1.length) ) { v.Error(T.cmap_SubtableOverlap, E.cmap_E_SubtableOverlap, m_tag, i.ToString() + " " + j.ToString()); bRet = false; bNoOverlap = true; } } } } if (bNoOverlap) { v.Pass(T.cmap_SubtableOverlap, P.cmap_P_SubtableOverlap, m_tag); } } else { v.Warning(T.cmap_SubtableOverlap, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate that no subtables overlap"); } } // Check that all subtable formats (First USHORT in the subtable) // is an even number between 0 and 14, inclusive. if (v.PerformTest(T.cmap_ValidFormat)) { bool bAllFormatsValid = true; for (uint i=0; i<NumberOfEncodingTables; i++) { EncodingTableEntry ete = GetEncodingTableEntry(i); if (ete.offset < m_bufTable.GetLength()-1) { // the format of the subtable is the first uint16 ushort format = m_bufTable.GetUshort(ete.offset); if (format > HIGHEST_FORMAT || ((format&1)==1)) { string sDetails = "PlatID = " + ete.platformID + ", EncID = " + ete.encodingID + ", Fmt = " + format; v.Error(T.cmap_ValidFormat, E.cmap_E_SubtableValidFormat, m_tag, sDetails); bRet = false; bAllFormatsValid = false; } } else { string sDetails = "PlatID = " + ete.platformID + ", EncID = " + ete.encodingID; string unable = "unable to validate format number for subtable - "; v.Warning(T.cmap_ValidFormat, W._TEST_W_OtherErrorsInTable, m_tag, unable + sDetails); bAllFormatsValid = false; } } if (bAllFormatsValid) { v.Pass(T.cmap_ValidFormat, P.cmap_P_SubtableValidFormat, m_tag); } } // Assuming maxp is present, get the number of glyphs from maxp, // and for each subtable, run its validate routine. if (v.PerformTest(T.cmap_SubtableInternalFormat)) { if (fontOwner.GetTable("maxp") == null) { string cant = "can't check subtable internal formats - " + "maxp table inaccessible"; v.Warning(T.cmap_SubtableInternalFormat, W._TEST_W_ErrorInAnotherTable, m_tag, cant ); } else { for (uint i=0; i<NumberOfEncodingTables; i++) { bool bInternalFormatOk = true; EncodingTableEntry ete = GetEncodingTableEntry(i); Subtable st = GetSubtable(ete); if (st != null) { ushort numGlyphs = fontOwner.GetMaxpNumGlyphs(); string sIdentity = "PlatID = " + ete.platformID + ", EncID = " + ete.encodingID + ", Fmt = " + st.format; ISubtableValidate valSubtable = (ISubtableValidate)st; bInternalFormatOk = valSubtable.Validate(v, this, numGlyphs, sIdentity); bRet &= bInternalFormatOk; if (bInternalFormatOk) { v.Pass(T.cmap_SubtableInternalFormat, P.cmap_P_InternalFormat, m_tag, sIdentity); } } else { string sDetails = "PlatID = " + ete.platformID + ", EncID = " + ete.encodingID; v.Warning(T.cmap_SubtableInternalFormat, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate internal format " + "for subtable - " + sDetails); } } } } // Pass if there is at least one subtable with platformID == 1 and // one subtable with platformID == 3. // Warn if either is missing. if (v.PerformTest(T.cmap_AppleMSSupport)) { bool bFoundApple = false; bool bFoundMS = false; for (uint i=0; i<NumberOfEncodingTables; i++) { EncodingTableEntry ete = GetEncodingTableEntry(i); if (ete.platformID == 1) { bFoundApple = true; } else if (ete.platformID == 3) { bFoundMS = true; } } if (bFoundApple && bFoundMS) { v.Pass(T.cmap_AppleMSSupport, P.cmap_P_AppleMSSupport, m_tag); } else if (!bFoundApple) { v.Warning(T.cmap_AppleMSSupport, W.cmap_W_AppleMSSupport_A, m_tag); } else if (!bFoundMS) { v.Warning(T.cmap_AppleMSSupport, W.cmap_W_AppleMSSupport_M, m_tag); } } // Find encoding table with platformID==1, encodingID==0 // i.e., Macintosh. Make sure that the Apple Logo, code point 240, // is mapped to glyphID 0, a legal requirement for Microsoft fonts // developed for use on Apple platforms. if (v.PerformTest(T.cmap_AppleLogo)) { EncodingTableEntry ete = GetEncodingTableEntry(1,0); if (ete != null) { Subtable st = GetSubtable(ete); if (st != null) { byte[] charbuf = new byte[2]; charbuf[0] = 240; charbuf[1] = 0; uint glyph = st.MapCharToGlyph(charbuf, 0); if (glyph == 0) { v.Pass(T.cmap_AppleLogo, P.cmap_P_AppleLogo, m_tag); } else { v.Warning(T.cmap_AppleLogo, W.cmap_W_AppleLogo, m_tag); } } else { string sDetails = "PlatID = " + ete.platformID + ", EncID = " + ete.encodingID; string unable = "unable to validate apple logo for subtable - "; v.Warning(T.cmap_AppleLogo, W._TEST_W_OtherErrorsInTable, m_tag, unable + sDetails); } } else { v.Warning(T.cmap_AppleLogo, W.cmap_W_AppleLogo_NoMap, m_tag); } } // Euro symbol. // Unless there is a Microsoft Symbol encoding cmap (3,0): // * Make sure that any apple cmap(1,0) contains a glyph U+00db // * Make sure that any Microsoft Unicode cmap (3,1) contains // a glyph U+20AC. if (v.PerformTest(T.cmap_EuroGlyph)) { EncodingTableEntry eteSym = GetEncodingTableEntry(3,0); if (eteSym == null) { EncodingTableEntry eteMac = GetEncodingTableEntry(1,0); if (eteMac != null) { Subtable st = GetSubtable(eteMac); if (st != null) { byte[] charbuf = new byte[2]; charbuf[0] = 0xdb; charbuf[1] = 0; uint glyph = st.MapCharToGlyph(charbuf, 0); if (glyph != 0) { v.Pass(T.cmap_EuroGlyph, P.cmap_P_EuroGlyph_Mac, m_tag); } else { v.Warning(T.cmap_EuroGlyph, W.cmap_W_EuroGlyph_Mac, m_tag); } } else { string sDetails = "PlatID = " + eteMac.platformID + ", EncID = " + eteMac.encodingID; string unable = "unable to validate if euro glyph " + "is present for subtable - "; v.Warning(T.cmap_EuroGlyph, W._TEST_W_OtherErrorsInTable, m_tag, unable + sDetails); } } EncodingTableEntry eteUni = GetEncodingTableEntry(3,1); if (eteUni != null) { Subtable st = GetSubtable(eteUni); if (st != null) { byte[] charbuf = new byte[2]; charbuf[0] = 0xac; charbuf[1] = 0x20; uint glyph = st.MapCharToGlyph(charbuf, 0); if (glyph != 0) { v.Pass(T.cmap_EuroGlyph, P.cmap_P_EuroGlyph_Uni, m_tag); } else { v.Warning(T.cmap_EuroGlyph, W.cmap_W_EuroGlyph_Uni, m_tag); } } else { string sDetails = "PlatID = " + eteMac.platformID + ", EncID = " + eteMac.encodingID; string unable = "unable to validate if euro glyph" + " is present for subtable - "; v.Warning(T.cmap_EuroGlyph, W._TEST_W_OtherErrorsInTable, m_tag, unable + sDetails); } } } } // Make sure that no glyphs, other than "fi" and "fl" ligatures, // are mapped from the "private use area", that is, // 0xE000 - 0xF8FF. The above ligatures may only be a the // prescribed places. // // Checks that 0xf001 and 0xfb01 map to the same place, and // Checks that 0xf002 and 0xfb02 map to the same place. // // Only warn if a problem. if (v.PerformTest(T.cmap_PrivateUse)) { EncodingTableEntry eteUni = GetEncodingTableEntry(3,1); if (eteUni != null) { Subtable st = GetSubtable(eteUni); if (st != null) { bool bFoundGlyph = false; bool bFoundLigChar = false; byte[] charbuf = new byte[2]; for (char c='\xe000'; c<'\xf8ff'; c++) { uint glyph = fontOwner.FastMapUnicodeToGlyphID(c); if (glyph != 0) { if (c == '\xf001') { // check to see if this is the 'fi' ligature uint glyph2 = fontOwner. FastMapUnicodeToGlyphID('\xfb01'); if (glyph == glyph2) { bFoundLigChar = true; } else { bFoundGlyph = true; break; } } else if (c == '\xf002') { // check to see if this is the 'fl' ligature uint glyph2 = fontOwner. FastMapUnicodeToGlyphID('\xfb02'); if (glyph == glyph2) { bFoundLigChar = true; } else { bFoundGlyph = true; break; } } else { bFoundGlyph = true; break; } } } if (bFoundGlyph) { v.Warning(T.cmap_PrivateUse, W.cmap_W_UnicodePrivateUse, m_tag); } else if (bFoundLigChar) { v.Pass(T.cmap_PrivateUse, P.cmap_P_UnicodePrivateUse_lig, m_tag); } else { v.Pass(T.cmap_PrivateUse, P.cmap_P_UnicodePrivateUse, m_tag); } } else { string sDetails = "PlatID = " + eteUni.platformID + ", EncID = " + eteUni.encodingID; v.Warning(T.cmap_PrivateUse, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate Private Use Area " + "for subtable - " + sDetails); } } } // Check that subtable language field is zero if not mac platform if (v.PerformTest(T.cmap_NonMacSubtableLanguage)) { bool bOk = true; for (uint i=0; i<NumberOfEncodingTables; i++) { EncodingTableEntry ete = GetEncodingTableEntry(i); Subtable st = GetSubtable(ete); if (st != null) { if (ete.platformID != 1) // not mac { if (st.language != 0) { string sDetails = "PlatID = " + ete.platformID + ", EncID = " + ete.encodingID + ", Language = " + st.language; v.Error(T.cmap_SubtableLanguage, E.cmap_E_NonMacSubtableLanguage, m_tag, sDetails); bOk = false; } } } } if (bOk) { v.Pass(T.cmap_SubtableLanguage, P.cmap_P_NonMacSubtableLanguage, m_tag); } } return bRet; }
bool Validate_indexSubTable_format4(Validator v, indexSubTable4 ist4, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); // header has already been validated // validate numGlyphs uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1; if (ist4.numGlyphs > nGlyphsInRange) { string sDetails = "numGlyphs is invalid: " + sID + ", numGlyphs = " + ist4.numGlyphs + ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex + ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // validate code offset pairs uint nEBDTLength = EBDTTable.GetLength(); for (ushort idGlyph=0; idGlyph<ist4.numGlyphs; idGlyph++) { indexSubTable4.codeOffsetPair cop = ist4.GetCodeOffsetPair(idGlyph); // glyph code if (cop.glyphCode < ista.firstGlyphIndex || cop.glyphCode > ista.lastGlyphIndex) { string sDetails = "glyph code is invalid: " + sID + ", codeOffsetPair[" + idGlyph + "]" + ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex + ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // offset if (cop.offset > nEBDTLength) { string sDetails = "invalid offset: " + sID + ", codeOffsetPair[" + idGlyph + "].offset = " + cop.offset + ", EBDT length = " + nEBDTLength; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } } return bOk; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; v.Info(T.T_NULL, I.CFF_I_Version, m_tag, major + "." + minor); if (major == 1 && minor == 0 && hdrSize == 4) { v.Pass(T.CFF_Header, P.CFF_P_Header, m_tag); } else { v.Error(T.CFF_Header, E.CFF_E_Header, m_tag, "major=" + major + ", minor=" + minor + ", hdrSize=" + hdrSize + ", offSize=" + offSize); } try { v.Pass(T.CFF_MAININDEX_Enumeration, P.CFF_P_MAININDEX_Enumeration, m_tag, "Name=" + Name.count + ", TopDICT=" + TopDICT.count + ", String=" + String.count + ", GlobalSubr=" + GlobalSubr.count); } catch (Exception e) { v.Error(T.CFF_MAININDEX_Enumeration, E.CFF_E_MAININDEX_Enumeration, m_tag, e.Message); return(false); } if (Name.count == TopDICT.count && TopDICT.count == 1) { v.Pass(T.CFF_NameDICTSize, P.CFF_P_NameDICTSize, m_tag); } else { v.Error(T.CFF_NameDICTSize, E.CFF_E_NameDICTSize, m_tag, "Name=" + Name.count + ", TopDICT=" + TopDICT.count); } if (Name.GetOffset(0) != 1) { v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "Name=" + Name.GetOffset(0)); } if (TopDICT.GetOffset(0) != 1) { v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "TopDICT=" + TopDICT.GetOffset(0)); } if (String.GetOffset(0) != 1) { v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "String=" + String.GetOffset(0)); } if (GlobalSubr.GetOffset(0) != 1) { v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "GlobalSubr=" + GlobalSubr.GetOffset(0)); } var overlap = new DataOverlapDetector(); if (!overlap.CheckForNoOverlap(0, hdrSize)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "hdrSize"); } if (!overlap.CheckForNoOverlap(Name.begin, Name.size)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "Name"); } if (!overlap.CheckForNoOverlap(TopDICT.begin, TopDICT.size)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "TopDICT"); } if (!overlap.CheckForNoOverlap(String.begin, String.size)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "String"); } if (!overlap.CheckForNoOverlap(GlobalSubr.begin, GlobalSubr.size)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "GlobalSubr"); } try { for (uint i = 0; i < Name.count; i++) { var name = Name.GetString(i); } v.Pass(T.CFF_Non_ASCII_String_or_Name, P.CFF_P_Non_ASCII_String_or_Name, m_tag, "Name INDEX"); } catch (DecoderFallbackException) { v.Error(T.CFF_Non_ASCII_String_or_Name, E.CFF_E_Non_ASCII_String_or_Name, m_tag, "Name INDEX"); } try{ for (uint i = 0; i < String.count; i++) { var a = String.GetString(i); } v.Pass(T.CFF_Non_ASCII_String_or_Name, P.CFF_P_Non_ASCII_String_or_Name, m_tag, "String INDEX"); } catch (DecoderFallbackException) { v.Error(T.CFF_Non_ASCII_String_or_Name, E.CFF_E_Non_ASCII_String_or_Name, m_tag, "String INDEX"); } for (uint iDICT = 0; iDICT < TopDICT.count; iDICT++) { Table_CFF.DICTData curTopDICT = null; try { curTopDICT = GetTopDICT(iDICT); v.Pass(T.CFF_DICTUnwind, P.CFF_P_DICTUnwind, m_tag, curTopDICT.FullName); if (!overlap.CheckForNoOverlap((uint)curTopDICT.offsetPrivate, (uint)curTopDICT.sizePrivate)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "TopDICTPriv"); } } catch (Exception e) { v.Error(T.CFF_DICTUnwind, E.CFF_E_DICTUnwind, m_tag, "TopDICT: " + e.Message); } Table_CFF.DICTData topPrivateDict = null; try { topPrivateDict = GetPrivate(curTopDICT); v.Pass(T.CFF_PrivDICTUnwind, P.CFF_P_PrivDICTUnwind, m_tag, "topPrivateDict"); } catch (Exception e) { v.Error(T.CFF_PrivDICTUnwind, E.CFF_E_PrivDICTUnwind, m_tag, "topPrivateDict: " + e.Message); } if (topPrivateDict != null && topPrivateDict.Subrs != 0) { try { Table_CFF.INDEXData topPrivSubrs = GetINDEX(curTopDICT.offsetPrivate + topPrivateDict.Subrs); v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "topPrivSubrs: " + topPrivSubrs.count); if (topPrivSubrs.GetOffset(0) != 1) { v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "topPrivSubrs=" + topPrivSubrs.GetOffset(0)); } if (!overlap.CheckForNoOverlap(topPrivSubrs.begin, topPrivSubrs.size)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "topPrivSubrs"); } } catch (Exception e) { v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "topPrivSubrs: " + e.Message); } } Table_CFF.INDEXData CharStrings = null; try { CharStrings = GetINDEX(curTopDICT.offsetCharStrings); v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "CharStrings: " + CharStrings.count); if (CharStrings.GetOffset(0) != 1) { v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "CharStrings=" + CharStrings.GetOffset(0)); } if (!overlap.CheckForNoOverlap(CharStrings.begin, CharStrings.size)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "CharStrings"); } } catch (Exception e) { v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "CharStrings: " + e.Message); } if (CharStrings.count == fontOwner.GetMaxpNumGlyphs()) { v.Pass(T.CFF_CharStringsCount, P.CFF_P_CharStringsCount, m_tag); } else { v.Error(T.CFF_CharStringsCount, E.CFF_E_CharStringsCount, m_tag, CharStrings.count.ToString() + "!=" + fontOwner.GetMaxpNumGlyphs()); } if (curTopDICT.ROS != null) { v.Info(T.CFF_CIDROS, I.CFF_I_CIDROS, m_tag, curTopDICT.ROS); } if (curTopDICT.offsetFDArray > 0) { Table_CFF.INDEXData FDArray = null; try { FDArray = GetINDEX(curTopDICT.offsetFDArray); v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "FDArray: " + FDArray.count); if (FDArray.GetOffset(0) != 1) { v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "FDArray=" + FDArray.GetOffset(0)); } if (!overlap.CheckForNoOverlap(FDArray.begin, FDArray.size)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "FDArray"); } } catch (Exception e) { v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "FDArray: " + e.Message); } for (uint i = 0; i < FDArray.count; i++) { Table_CFF.DICTData FDict = null; try { FDict = GetDICT(FDArray.GetData(i)); v.Pass(T.CFF_DICTUnwind, P.CFF_P_DICTUnwind, m_tag, "CID FontDict #" + i + ": " + FDict.FontName); if (!overlap.CheckForNoOverlap((uint)FDict.offsetPrivate, (uint)FDict.sizePrivate)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "FDictPriv#" + i); } } catch (Exception e) { v.Error(T.CFF_DICTUnwind, E.CFF_E_DICTUnwind, m_tag, "CID FontDict #" + i + ": " + e.Message); } Table_CFF.DICTData FDictPrivate = null; try { FDictPrivate = GetPrivate(FDict); v.Pass(T.CFF_PrivDICTUnwind, P.CFF_P_PrivDICTUnwind, m_tag, "CID FontDict Private DICT#" + i); } catch (Exception e) { v.Error(T.CFF_PrivDICTUnwind, E.CFF_E_PrivDICTUnwind, m_tag, "CID FontDict Private DICT#" + i + ": " + e.Message); } if (FDictPrivate != null && FDictPrivate.Subrs != 0) { Table_CFF.INDEXData PrivSubrs = null; try { PrivSubrs = GetINDEX(FDict.offsetPrivate + FDictPrivate.Subrs); v.Pass(T.CFF_INDEXCount, P.CFF_P_INDEXCount, m_tag, "PrivSubrs#" + i + ": " + PrivSubrs.count); if (PrivSubrs.GetOffset(0) != 1) { v.Warning(T.CFF_INDEXFirstOffset, W.CFF_W_INDEXFirstOffset, m_tag, "PrivSubrs#" + i + "=" + PrivSubrs.GetOffset(0)); } if (!overlap.CheckForNoOverlap(PrivSubrs.begin, PrivSubrs.size)) { v.Error(T.CFF_StructOverlap, E.CFF_E_StructOverlap, m_tag, "PrivSubrs#" + i); } ; } catch (Exception e) { v.Error(T.CFF_INDEXCount, E.CFF_E_INDEXCount, m_tag, "PrivSubrs#" + i + ": " + e.Message); } } } } string result = "Tested Region: " + overlap.Occupied + " of " + GetLength() + ", not testing" + (curTopDICT.offsetCharset == 0 ? "" : " Charset: " + curTopDICT.offsetCharset) + (curTopDICT.offsetEncoding == 0 ? "" : " Encoding: " + curTopDICT.offsetEncoding) + (curTopDICT.offsetFDSelect == 0 ? "" : " FDSelect: " + curTopDICT.offsetFDSelect); v.Info(T.CFF_TestCoverage, I.CFF_I_NotValidated, m_tag, result); } return(bRet); }
bool Validate_indexSubTable_format2(Validator v, indexSubTable2 ist2, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); // header has already been validated // validate the image size uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1; if (nGlyphsInRange * ist2.imageSize > EBDTTable.GetLength()) { string sDetails = "images extend past end of EBDT table: " + sID + ", imageSize = " + ist2.imageSize + ", EBDT length = " + EBDTTable.GetLength(); v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // validate the bigGlyphMetrics val_EBDT.bigGlyphMetrics_val bgm = val_EBDT.bigGlyphMetrics_val.CreateFromBigGlyphMetrics(ist2.bigMetrics); bgm.Validate(v, sID, this); return(bOk); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.post_TableLength)) { bool bLenOk = true; if (Version.GetUint() == 0x00010000 || Version.GetUint() == 0x00030000) { if (GetLength() != 32) { v.Error(T.post_TableLength, E.post_E_TableLenNot32, m_tag); bLenOk = false; bRet = false; } } if (Version.GetUint() == 0x00020000) { if (GetLength() < 34) { v.Error(T.post_TableLength, E.post_E_InvalidTableLen, m_tag); bLenOk = false; bRet = false; } } if (bLenOk) { v.Pass(T.post_TableLength, P.post_P_TableLength, m_tag); } } if (v.PerformTest(T.post_Version)) { uint ver = Version.GetUint(); if (ver == 0x00025000) { v.Warning(T.post_Version, W.post_W_Version_2_5, m_tag); } else if (ver == 0x00010000 || ver == 0x00020000) { v.Pass(T.post_Version, P.post_P_Version, m_tag); } else if (ver == 0x00030000) { v.Warning(T.post_Version, W.post_W_Version_3_Apple, m_tag); } else if (ver == 0x00040000) { v.Warning(T.post_Version, W.post_W_Version_4_Apple, m_tag); } else { v.Error(T.post_Version, E.post_E_Version, m_tag, "0x" + ver.ToString("x8")); } } if (v.PerformTest(T.post_italicAngle)) { bool bItalOk = true; uint ia = italicAngle.GetUint(); double dItalicAngle = italicAngle.GetDouble(); if (dItalicAngle < -30.0 || dItalicAngle > 360.0 || (dItalicAngle > 0.0 && dItalicAngle < 330.0)) { v.Warning(T.post_italicAngle, W.post_W_italicAngle_unlikely, m_tag, "0x" + ia.ToString("x8")); bItalOk = false; } Table_head headTable = (Table_head)fontOwner.GetTable("head"); if (headTable != null) { if ((headTable.macStyle & 0x0002) != 0) { if (ia == 0) { v.Error(T.post_italicAngle, E.post_E_italicAngleZero_macStyle, m_tag); bItalOk = false; bRet = false; } } else { if (ia != 0) { v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_macStyle, m_tag); bItalOk = false; bRet = false; } } } else { v.Error(T.post_italicAngle, E._TEST_E_TableMissing, m_tag, "head table missing, can't compare italicAngle to head.macStyle"); bItalOk = false; } Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea"); if (hheaTable != null) { if (ia == 0) { if (hheaTable.caretSlopeRun != 0) { v.Error(T.post_italicAngle, E.post_E_italicAngleZero_caretSlopeRun, m_tag); bItalOk = false; bRet = false; } } else { if (hheaTable.caretSlopeRun == 0) { v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_caretSlopeRun, m_tag); bItalOk = false; bRet = false; } else { double dActualAngle = 90.0 + italicAngle.GetDouble(); double dhheaAngle = (Math.Atan2(hheaTable.caretSlopeRise, hheaTable.caretSlopeRun)) * (180.0 / Math.PI); if (Math.Abs(dActualAngle - dhheaAngle) >= 1.0) { string sDetails = "italicAngle = 0x" + ia.ToString("x8") + " (" + italicAngle.GetDouble() + " degrees)" + ",caretSlope Rise:Run = " + hheaTable.caretSlopeRise + ":" + hheaTable.caretSlopeRun + " (" + (dhheaAngle - 90.0) + " degrees)"; v.Error(T.post_italicAngle, E.post_E_italicAngleNonzero_hheaAngle, m_tag, sDetails); bItalOk = false; bRet = false; } } } } else { v.Error(T.post_italicAngle, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare italicAngle to hhea.caretSlopeRun"); bItalOk = false; bRet = false; } if (bItalOk) { v.Pass(T.post_italicAngle, P.post_P_italicAngle, m_tag); } } if (v.PerformTest(T.post_underlinePosition)) { Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea"); if (hheaTable != null) { if (underlinePosition >= hheaTable.Descender) { v.Pass(T.post_underlinePosition, P.post_P_underlinePosition, m_tag); } else { v.Warning(T.post_underlinePosition, W.post_W_underlinePos_LT_descender, m_tag); //bRet = false; } } else { v.Error(T.post_underlinePosition, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare underlinePosition to hhea.Descender"); } } if (v.PerformTest(T.post_underlineThickness)) { Table_head headTable = (Table_head)fontOwner.GetTable("head"); if (headTable != null) { if (underlineThickness >= 0 && underlineThickness < headTable.unitsPerEm / 2) { v.Pass(T.post_underlineThickness, P.post_P_underlineThickness, m_tag); } else { v.Warning(T.post_underlineThickness, W.post_W_underlineThickness, m_tag, underlineThickness.ToString()); } } else { v.Error(T.post_underlineThickness, E._TEST_E_TableMissing, m_tag, "head table missing, can't compare underlineThickness to head.unitsPerEm"); bRet = false; } } if (v.PerformTest(T.post_isFixedPitch)) { bool bFixedPitchOk = true; Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx"); if (hmtxTable != null) { uint numberOfHMetrics = 0; Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea"); if (hheaTable != null) { numberOfHMetrics = hheaTable.numberOfHMetrics; } else { v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing, m_tag, "hhea table missing, can't compare isFixedPitch to horizontal metrics"); bRet = false; } bool bHmtxMono = hmtxTable.IsMonospace(fontOwner); if (isFixedPitch == 0 && bHmtxMono) { v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchZero_hmtx, m_tag); bFixedPitchOk = false; bRet = false; } else if (isFixedPitch != 0 && !bHmtxMono) { v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchNonzero_hmtx, m_tag); bFixedPitchOk = false; bRet = false; } } else { v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing, m_tag, "hmtx table missing, can't compare isFixedPitch to horizontal metrics"); bRet = false; } Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2"); if (OS2Table != null) { if (OS2Table.panose_byte1 == 2) // PANOSE family kind == LatinText { if (isFixedPitch == 0 && OS2Table.panose_byte4 == 9) // PANOSE proportion == monospaced { v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchZero_OS_2, m_tag); bFixedPitchOk = false; bRet = false; } else if (isFixedPitch != 0 && OS2Table.panose_byte4 != 9) { v.Error(T.post_isFixedPitch, E.post_E_isFixedPitchNonzero_OS_2, m_tag); bFixedPitchOk = false; bRet = false; } } } else { v.Error(T.post_isFixedPitch, E._TEST_E_TableMissing, m_tag, "OS/2 table is missing, can't compare isFixedPitch to OS/2 PANOSE"); bRet = false; } if (bFixedPitchOk && hmtxTable != null && OS2Table != null) { v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the hmtx and OS/2 tables"); } else if (bFixedPitchOk && hmtxTable == null && OS2Table != null) { v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the OS/2 table"); } else if (bFixedPitchOk && hmtxTable != null && OS2Table == null) { v.Pass(T.post_isFixedPitch, P.post_P_isFixedPitch, m_tag, "matches the hmtx table"); } } if (v.PerformTest(T.post_v2_numberOfGlyphs)) { if (Version.GetUint() == 0x00020000) { Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (maxpTable == null) { v.Error(T.post_v2_numberOfGlyphs, E._TEST_E_TableMissing, m_tag, "maxp table is missing"); bRet = false; } else { if (numberOfGlyphs == fontOwner.GetMaxpNumGlyphs()) { v.Pass(T.post_v2_numberOfGlyphs, P.post_P_v2_numberOfGlyphs, m_tag); } else { v.Error(T.post_v2_numberOfGlyphs, E.post_E_v2_numberOfGlyphs, m_tag, "numberOfGlyphs = " + numberOfGlyphs + ", maxp.numGlyphs = " + fontOwner.GetMaxpNumGlyphs()); bRet = false; } } } else { v.Info(T.post_v2_numberOfGlyphs, I.post_I_v2_numberOfGlyphs_notv2, m_tag); } } if (v.PerformTest(T.post_v2_glyphNameIndex)) { if (Version.GetUint() == 0x00020000 && GetLength() >= 34) { bool bIndexOk = true; for (uint i = 0; i < numberOfGlyphs; i++) { if ((uint)FieldOffsetsVer2.glyphNameIndex + i * 2 + 2 <= m_bufTable.GetLength()) { ushort index = GetGlyphNameIndex((ushort)i); if (index - 258 >= m_nameOffsets.Length) { string s = "glyphNameIndex[" + i + "] = " + index + ", # names = " + m_nameOffsets.Length; v.Error(T.post_v2_glyphNameIndex, E.post_E_glyphNameIndex_range, m_tag, s); bIndexOk = false; bRet = false; } } else { v.Warning(T.post_v2_glyphNameIndex, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate any more glyph indexes, index " + i + " is past end of table"); bIndexOk = false; break; } } if (bIndexOk) { v.Pass(T.post_v2_glyphNameIndex, P.post_P_glyphNameIndex, m_tag); } } else { v.Info(T.post_v2_glyphNameIndex, I.post_I_v2_glyphNameIndex_notv2, m_tag); } } if (v.PerformTest(T.post_v2_names)) { if (Version.GetUint() == 0x00020000) { PostNames pn = new PostNames(); bool bNamesOk = true; byte [] buf = new byte[2]; for (uint iGlyph = 0; iGlyph < numberOfGlyphs; iGlyph++) { if ((uint)FieldOffsetsVer2.glyphNameIndex + iGlyph * 2 + 2 <= m_bufTable.GetLength()) { uint index = GetGlyphNameIndex((ushort)iGlyph); if (index >= 258 && index - 258 < m_nameOffsets.Length) { if (m_nameOffsets[index - 258] >= GetLength()) { string s = "name index = " + index; v.Error(T.post_v2_names, E.post_E_v2_NameOffsetInvalid, m_tag, s); bNamesOk = false; bRet = false; } else { uint length = m_bufTable.GetByte(m_nameOffsets[index - 258]); if (m_nameOffsets[index - 258] + length < GetLength()) { bNamesOk = CheckNames(v, fontOwner, pn, iGlyph, index); } else { string s = "name index = " + index; v.Error(T.post_v2_names, E.post_E_v2_NameLengthInvalid, m_tag, s); bNamesOk = false; bRet = false; } } } } else { v.Warning(T.post_v2_names, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate any more names, index " + iGlyph + " is past end of table"); bNamesOk = false; break; } } if (bNamesOk) { v.Pass(T.post_v2_names, P.post_P_names, m_tag); } } else { v.Info(T.post_v2_names, I.post_I_v2_names_notv2, m_tag); } } return(bRet); }
private bool CheckNames(Validator v, OTFontVal fontOwner, PostNames pn, uint iGlyph, uint index) { bool bNamesOk = true; string sName = GetNameString(index - 258); System.Globalization.NumberStyles hexStyle = System.Globalization.NumberStyles.HexNumber; if (Is_uniXXXX(sName)) { char c = (char)Int16.Parse(sName.Substring(3, 4), hexStyle); if (fontOwner.FastMapUnicodeToGlyphID(c) != iGlyph) { char cMapped = fontOwner.MapGlyphIDToUnicode(iGlyph, (char)0); string s = "glyph = " + iGlyph + ", char = U+" + ((uint)cMapped).ToString("X4") + ", name = " + sName; v.Info(T.post_v2_names, I.post_I_names_uni_unexpected, m_tag, s); bNamesOk = false; } } else if (Is_uXXXXX(sName)) { uint c = (uint)Int32.Parse(sName.Substring(1), hexStyle); if (c < 0xffff) { if (fontOwner.FastMapUnicodeToGlyphID((char)c) != iGlyph) { char cMapped = fontOwner.MapGlyphIDToUnicode(iGlyph, (char)0); string s = "glyph = " + iGlyph + ", char = U+" + ((uint)cMapped).ToString("X4") + ", name = " + sName; v.Info(T.post_v2_names, I.post_I_names_uni_unexpected, m_tag, s); bNamesOk = false; } } else { if (fontOwner.FastMapUnicode32ToGlyphID(c) != iGlyph) { uint cMapped = fontOwner.MapGlyphIDToUnicode32(iGlyph, 0); string s = "glyph = " + iGlyph + ", char = U+" + ((uint)cMapped).ToString("X5") + ", name = " + sName; v.Info(T.post_v2_names, I.post_I_names_uni_unexpected, m_tag, s); bNamesOk = false; } } } else { // check the Adobe Glyph Names char c = (char)fontOwner.MapGlyphIDToUnicode(iGlyph, (char)0); if (c != 0xffff) { string sAdobeName = pn.GetAdobeGlyphName(c); if (sAdobeName == null) { string s = "glyph = " + iGlyph + ", char = U+" + ((uint)c).ToString("X4") + ", name = " + sName; v.Info(T.post_v2_names, I.post_I_names_noAdobe, m_tag, s); bNamesOk = false; } else if (sName != sAdobeName) { string s = "glyph = " + iGlyph + ", char = U+" + ((uint)c).ToString("X4") + ", name = " + sName; v.Info(T.post_v2_names, I.post_I_names_nomatch, m_tag, s); bNamesOk = false; } } } return(bNamesOk); }
public bool Validate(Validator validator, OTFontVal fontOwner) { bool bRet = true; if (!validator.PerformTest(T.glyf_ValidateAll)) { return true; } this.m_diaValidate=validator.DIA; this.m_cnts=new int[this.m_namesInfoCnt.Length]; for (int iCnt=0; iCnt<this.m_cnts.Length; iCnt++) { this.m_cnts[iCnt]=0; } I_IOGlyphsFile i_IOGlyphs=new I_IOGlyphsFile(); if (!i_IOGlyphs.Initialize(fontOwner,validator)) { return false; // the error is already reported } DIAction diaFilter= DIActionBuilder.DIA(this,"DIAFunc_Filter"); FManager fm=new FManager(i_IOGlyphs, null, null); int numGlyph=fm.FNumGlyph; int indGlyph; for (indGlyph=0; indGlyph<numGlyph; indGlyph++) { try { validator.OnTableProgress("Validating glyph with index "+indGlyph+" (out of "+numGlyph+" glyphs)"); Glyph glyph=fm.GGet(indGlyph); glyph.GValidate(); bRet &= fm.GErrGetInformed(indGlyph,diaFilter); fm.ClearManagementStructs(); } catch { validator.Error(T.T_NULL, E.glyf_E_ExceptionUnhandeled, (OTTag)"glyf", "Glyph index "+indGlyph); } if (validator.CancelFlag) break; } i_IOGlyphs.Clear(); fm.ClearDestroy(); fm=null; /* I_ProgressUpdater i_ProgressUpdater=new ValidationCancel(validator); FManager fm=new FManager(i_IOGlyphs, null, null); DIAction diaFilter= DIActionBuilder.DIA(this,"DIAFunc_Filter"); fm.GErrActionAdd(diaFilter, FManager.TypeActionOnErr.onAdd); fm.FValidate(GConsts.IND_UNINITIALIZED, GConsts.IND_UNINITIALIZED); i_IOGlyphs.Clear(); i_ProgressUpdater.Clear(); fm.ClearDestroy(); fm=null; */ for (int iCnt=0; iCnt<this.m_cnts.Length; iCnt++) { if (this.m_cnts[iCnt]>0) { bool isGErr=this.m_namesInfoCnt[iCnt].StartsWith("GERR_"); string nameFileErr=isGErr? GErrConsts.FILE_RES_GERR_STRINGS: GErrConsts.FILE_RES_OTFFERR_STRINGS; string nameAsmFileErr=isGErr? GErrConsts.ASM_RES_GERR_STRINGS: GErrConsts.ASM_RES_OTFFERR_STRINGS; string strDetails="Number of glyphs with the warning = "+this.m_cnts[iCnt]; if (validator.CancelFlag) strDetails+=" (Validation cancelled)"; ValInfoBasic info=new ValInfoBasic( ValInfoBasic.ValInfoType.Warning, this.m_namesInfoCnt[iCnt], strDetails, nameFileErr, nameAsmFileErr, "glyf", null); validator.DIA(info); } } this.m_cnts=null; return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.GDEF_Version)) { if (Version.GetUint() == 0x00010000 || Version.GetUint() == 0x00010002 ) { v.Pass(T.GDEF_Version, P.GDEF_P_Version, m_tag, "0x"+ Version.GetUint().ToString("x8")); } else { v.Error(T.GDEF_Version, E.GDEF_E_Version, m_tag, "0x" + Version.GetUint().ToString("x8")); } } if (v.PerformTest(T.GDEF_HeaderOffsets)) { bool bOffsetsOk = true; if (GlyphClassDefOffset != 0) { if (GlyphClassDefOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "GlyphClassDef"); bOffsetsOk = false; bRet = false; } } if (AttachListOffset != 0) { if (AttachListOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "AttachList"); bOffsetsOk = false; bRet = false; } } if (LigCaretListOffset != 0) { if (LigCaretListOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "LigCaretList"); bOffsetsOk = false; bRet = false; } } if (MarkAttachClassDefOffset != 0) { if (MarkAttachClassDefOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "MarkAttachClassDef"); bOffsetsOk = false; bRet = false; } } if (MarkGlyphSetsDefOffset != 0) { if (MarkGlyphSetsDefOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "MarkGlyphSetsDef"); bOffsetsOk = false; bRet = false; } } if (bOffsetsOk == true) { v.Pass(T.GDEF_HeaderOffsets, P.GDEF_P_HeaderOffsets, m_tag); } } if (v.PerformTest(T.GDEF_Subtables)) { if (GlyphClassDefOffset != 0) { ClassDefTable_val cdt = GetGlyphClassDefTable_val(); cdt.Validate(v, "GlyphClassDef", this); } if (AttachListOffset != 0) { AttachListTable_val alt = GetAttachListTable_val(); alt.Validate(v, "AttachList", this); } if (LigCaretListOffset != 0) { LigCaretListTable_val lclt = GetLigCaretListTable_val(); lclt.Validate(v, "LigCaretList", this); } if (MarkAttachClassDefOffset != 0) { ClassDefTable_val macdt = GetMarkAttachClassDefTable_val(); macdt.Validate(v, "MarkAttachClassDef", this); } if (MarkGlyphSetsDefOffset != 0) { MarkGlyphSetsDefTable_val mgsdt = GetMarkGlyphSetsDefTable_val(); mgsdt.Validate(v, "MarkGlyphSetsDef", this); } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.name_FormatSelector)) { if (FormatSelector == 0) { v.Pass(T.name_FormatSelector, P.name_P_FormatSelector, m_tag); } else { v.Error(T.name_FormatSelector, E.name_E_FormatSelector, m_tag, FormatSelector.ToString()); bRet = false; } } if (v.PerformTest(T.name_StringsWithinTable)) { bool bStringsWithinTable = true; uint tableLength = GetLength(); for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.StringOffset + nr.StringLength > tableLength) { v.Error(T.name_StringsWithinTable, E.name_E_StringsWithinTable, m_tag, "string# " + i); bStringsWithinTable = false; bRet = false; } } else { v.Warning(T.name_StringsWithinTable, W._TEST_W_OtherErrorsInTable, m_tag); bStringsWithinTable = false; break; } } if (bStringsWithinTable) { v.Pass(T.name_StringsWithinTable, P.name_P_StringsWithinTable, m_tag); } } if (v.PerformTest(T.name_NameRecordsSorted)) { bool bSortedOrder = true; if (NumberNameRecords > 1) { NameRecord CurrNR = GetNameRecord(0); NameRecord NextNR = null; for (uint i=0; i<NumberNameRecords-1; i++) { NextNR = GetNameRecord(i+1); if (CurrNR == null || NextNR == null) { bSortedOrder = false; break; } if (CurrNR.PlatformID > NextNR.PlatformID) { bSortedOrder = false; break; } else if (CurrNR.PlatformID == NextNR.PlatformID) { if (CurrNR.EncodingID > NextNR.EncodingID) { bSortedOrder = false; break; } else if (CurrNR.EncodingID == NextNR.EncodingID) { if (CurrNR.LanguageID > NextNR.LanguageID) { bSortedOrder = false; break; } else if (CurrNR.LanguageID == NextNR.LanguageID) { if (CurrNR.NameID > NextNR.NameID) { bSortedOrder = false; break; } } } } CurrNR = NextNR; } } if (bSortedOrder) { v.Pass(T.name_NameRecordsSorted, P.name_P_NameRecordsSorted, m_tag); } else { v.Error(T.name_NameRecordsSorted, E.name_E_NameRecordsSorted, m_tag); bRet = false; } } if (v.PerformTest(T.name_ReservedNameIDs)) { bool bReservedOk = true; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID >= 21 && nr.NameID <= 255) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_ReservedNameIDs, E.name_E_ReservedNameID, m_tag, s); bReservedOk = false; break; } } else { v.Warning(T.name_ReservedNameIDs, W._TEST_W_OtherErrorsInTable, m_tag); bReservedOk = false; break; } } if (bReservedOk) { v.Pass(T.name_ReservedNameIDs, P.name_P_ReservedNameID, m_tag); } } if (v.PerformTest(T.name_BothPlatforms)) { bool bMac = false; bool bMS = false; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 1) { bMac = true; } else if (nr.PlatformID == 3) { bMS = true; } } } if (bMac && bMS) { v.Pass(T.name_BothPlatforms, P.name_P_BothPlatforms, m_tag); } else if (!bMac) { v.Error(T.name_BothPlatforms, E.name_E_NoMacPlatform, m_tag); bRet = false; } else if (!bMS) { v.Error(T.name_BothPlatforms, E.name_E_NoMSPlatform, m_tag); bRet = false; } } if (v.PerformTest(T.name_VersionString)) { bool bFound = false; string sVersion = ""; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 3 // ms && (nr.EncodingID == 1 /* unicode */ || nr.EncodingID == 0 /*symbol*/) && nr.NameID == 5) // version string { bFound = true; bool bVerStringValid = false; byte [] buf = GetEncodedString(nr); string s = ""; if (buf != null) { sVersion = ""; for (int j=0; j<buf.Length/2; j++) { char c = (char)(ushort)(buf[j*2]<<8 | buf[j*2+1]); sVersion += c; } if (sVersion.Length >= 11 && sVersion.StartsWith("Version ") && Char.IsDigit(sVersion, 8)) { int j = 9; // advance past the digits in the major number while (j < sVersion.Length) { if (Char.IsDigit(sVersion, j)) { j++; } else { break; } } // if major number is followed by a period if (sVersion[j] == '.') { // advance past the period j++; // check for a digit if (Char.IsDigit(sVersion, j)) { bVerStringValid = true; } } } } s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", \"" + sVersion + "\""; if (bVerStringValid) { v.Pass(T.name_VersionString, P.name_P_VersionStringFormat, m_tag, s); } else { v.Error(T.name_VersionString, E.name_E_VersionStringFormat, m_tag, s); bRet = false; } // compare to mac version string if present string sMacVer = GetString(1, 0, 0xffff, 5); if (sMacVer != null) { if (sVersion.CompareTo(sMacVer) != 0) { v.Warning(T.name_VersionString, W.name_W_VersionMismatch_MS_MAC, m_tag); } } // compare to 3,10 version string if present string s310Ver = GetString(3, 10, nr.LanguageID, 5); if (s310Ver != null) { if (sVersion.CompareTo(s310Ver) != 0) { string s310 = "platID = 3, encID = 10, langID = " + nr.LanguageID + ", \"" + s310Ver + "\""; v.Warning(T.name_VersionString, W.name_W_VersionMismatch_3_1_3_10, m_tag, s + " / " + s310); } } } } } if (!bFound) { v.Error(T.name_VersionString, E.name_E_VersionStringNotFound, m_tag); bRet = false; } } if (v.PerformTest(T.name_PlatformSpecificEncoding)) { bool bIDsOk = true; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 0) // unicode { if (nr.EncodingID > 3) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s); bIDsOk = false; bRet = false; } } else if (nr.PlatformID == 1) // mac { if (nr.EncodingID > 32) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s); bIDsOk = false; bRet = false; } } else if (nr.PlatformID == 2) // iso { if (nr.EncodingID > 2) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s); bIDsOk = false; bRet = false; } } else if (nr.PlatformID == 3) // MS { if (nr.EncodingID > 10) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID; v.Error(T.name_PlatformSpecificEncoding, E.name_E_PlatformSpecificEncoding, m_tag, s); bIDsOk = false; bRet = false; } } /* else if (nr.PlatformID == 4) // Custom { } */ } else { v.Warning(T.name_PlatformSpecificEncoding, W._TEST_W_OtherErrorsInTable, m_tag); bIDsOk = false; break; } } if (bIDsOk) { v.Pass(T.name_PlatformSpecificEncoding, P.name_P_PlatformSpecificEncoding, m_tag); } } if (v.PerformTest(T.name_MSLanguageIDs)) { bool bFound = false; bool bIDsOk = true; ushort [] MSLangIDs = // taken from Q224804 { 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, 0x0408, 0x0409, 0x040a, 0x040b, 0x040c, 0x040D, 0x040e, 0x040F, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041a, 0x041b, 0x041c, 0x041D, 0x041E, 0x041f, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0429, 0x042a, 0x042b, 0x042c, 0x042D, 0x042e, 0x042f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043b, 0x043d, 0x043e, 0x043f, 0x0441, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044a, 0x044b, 0x044c, 0x044d, 0x044e, 0x044f, 0x0457, 0x0459, 0x0461, 0x0801, 0x0804, 0x0807, 0x0809, 0x080a, 0x080c, 0x0810, 0x0812, 0x0813, 0x0814, 0x0816, 0x0818, 0x0819, 0x081a, 0x081d, 0x0820, 0x0827, 0x082c, 0x083e, 0x0843, 0x0860, 0x0861, 0x0C01, 0x0C04, 0x0c07, 0x0c09, 0x0c0a, 0x0c0c, 0x0c1a, 0x1001, 0x1004, 0x1007, 0x1009, 0x100a, 0x100c, 0x1401, 0x1404, 0x1407, 0x1409, 0x140a, 0x140c, 0x1801, 0x1809, 0x180a, 0x180c, 0x1C01, 0x1c09, 0x1c0a, 0x2001, 0x2009, 0x200a, 0x2401, 0x2409, 0x240a, 0x2801, 0x2809, 0x280a, 0x2C01, 0x2c09, 0x2c0a, 0x3001, 0x3009, 0x300a, 0x3401, 0x3409, 0x340a, 0x3801, 0x380a, 0x3C01, 0x3c0a, 0x4001, 0x400a, 0x440a, 0x480a, 0x4c0a, 0x500a }; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 3 && nr.EncodingID == 1) { bFound = true; bool bValidID = false; for (uint j=0; j<MSLangIDs.Length; j++) { if (nr.LanguageID == MSLangIDs[j]) { bValidID = true; break; } } if (!bValidID) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = 0x" + nr.LanguageID.ToString("x4") + ", nameID = " + nr.NameID; v.Error(T.name_MSLanguageIDs, E.name_E_MSLanguageID, m_tag, s); bIDsOk = false; bRet = false; } } } } if (bFound && bIDsOk) { v.Pass(T.name_MSLanguageIDs, P.name_P_MSLanguageID, m_tag); } } if (v.PerformTest(T.name_unicode_length)) { bool bLengthsOk = true; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.PlatformID == 0 || nr.PlatformID == 2 || // unicode or iso platform (nr.PlatformID == 3 && nr.EncodingID == 1)) // microsoft platform, unicode encoding { if ((nr.StringLength & 1) == 1) { string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID + ", length = " + nr.StringLength; v.Error(T.name_unicode_length, E.name_E_UnicodeLength, m_tag, s); bLengthsOk = false; bRet = false; } } } else { v.Warning(T.name_unicode_length, W._TEST_W_OtherErrorsInTable, m_tag); bLengthsOk = false; break; } } if (bLengthsOk) { v.Pass(T.name_unicode_length, P.name_P_UnicodeLength, m_tag); } } if (v.PerformTest(T.name_Postscript)) { bool bPostscriptOk = true; string sPostscriptMac = GetString(1, 0, 0, 6); if (sPostscriptMac != null) { if (sPostscriptMac.Length > 63) { v.Error(T.name_Postscript, E.name_E_Postscript_length, m_tag, "name string (1, 0, 0, 6) is " + sPostscriptMac.Length + " characters long"); bRet = false; bPostscriptOk = false; } for (int i=0; i<sPostscriptMac.Length; i++) { char c = sPostscriptMac[i]; if (c < 33 || c > 126 || c=='[' || c==']' || c=='(' || c==')' || c=='{' || c=='}' || c=='<' || c=='>' || c=='/' || c=='%') { v.Error(T.name_Postscript, E.name_E_Postscript_chars, m_tag, "name string (1, 0, 0, 6) contains an illegal character at index " + i); bRet = false; bPostscriptOk = false; } } } ushort nEncoding = 1; if (fontOwner.ContainsMsSymbolEncodedCmap()) { nEncoding = 0; } string sPostscriptMS = GetString(3, nEncoding, 0x409, 6); // ms if (sPostscriptMS != null) { if (sPostscriptMS.Length > 63) { v.Error(T.name_Postscript, E.name_E_Postscript_length, m_tag, "name string (3, " + nEncoding + ", 0x409, 6) is " + sPostscriptMS.Length + " characters long"); bRet = false; bPostscriptOk = false; } for (int i=0; i<sPostscriptMS.Length; i++) { char c = sPostscriptMS[i]; if (c < 33 || c > 126 || c=='[' || c==']' || c=='(' || c==')' || c=='{' || c=='}' || c=='<' || c=='>' || c=='/' || c=='%') { v.Error(T.name_Postscript, E.name_E_Postscript_chars, m_tag, "name string (3, " + nEncoding + ", 0x409, 6) contains an illegal character at index " + i); bRet = false; bPostscriptOk = false; } } } if (sPostscriptMac==null && sPostscriptMS!=null) { v.Error(T.name_Postscript, E.name_E_Postscript_missing, m_tag, "Mac Postscript string is missing, but MS Postscript string is present"); bRet = false; bPostscriptOk = false; } else if (sPostscriptMac!=null && sPostscriptMS==null) { v.Error(T.name_Postscript, E.name_E_Postscript_missing, m_tag, "MS Postscript string is missing, but Mac Postscript string is present"); bRet = false; bPostscriptOk = false; } if (sPostscriptMac!=null && sPostscriptMS!=null) { if (sPostscriptMac != sPostscriptMS) { v.Error(T.name_Postscript, E.name_E_Postscript_unequal, m_tag, "mac postscript = " + sPostscriptMac + ", MS postscript = " + sPostscriptMS ); bRet = false; bPostscriptOk = false; } } if (sPostscriptMac!=null && sPostscriptMS!=null && bPostscriptOk) { v.Pass(T.name_Postscript, P.name_P_Postscript, m_tag); } } if (v.PerformTest(T.name_Subfamily)) { string sStyle = GetStyleString(); if (sStyle != null) { Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2"); if (OS2Table != null) { bool bStyleOk = true; string sStyleDetails = ""; string s = sStyle.ToLower(); bool bItalic = ((OS2Table.fsSelection & 0x01) != 0 ); bool bBold = ((OS2Table.fsSelection & 0x20) != 0 ); if (bItalic) { if (s.IndexOf("italic") == -1 && s.IndexOf("oblique") == -1) { bStyleOk = false; sStyleDetails = "OS/2.fsSelection italic bit is set, but subfamily string = '" + sStyle + "'"; } } else { if (s.IndexOf("italic") != -1 || s.IndexOf("oblique") != -1) { bStyleOk = false; sStyleDetails = "OS/2.fsSelection italic bit is clear, but subfamily string = '" + sStyle + "'"; } } if (bBold) { if (s.IndexOf("bold") == -1) { bStyleOk = false; sStyleDetails = "OS/2.fsSelection bold bit is set, but subfamily string = '" + sStyle + "'"; } } else { if (s.IndexOf("bold") != -1) { bStyleOk = false; sStyleDetails = "OS/2.fsSelection bold bit is clear, but subfamily string = '" + sStyle + "'"; } } if (bStyleOk) { v.Pass(T.name_Subfamily, P.name_P_subfamily, m_tag); } else { v.Warning(T.name_Subfamily, W.name_W_subfamily_style, m_tag, sStyleDetails); } } } } if (v.PerformTest(T.name_NoFormat14)) { bool bStringOK = true; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null && nr.NameID == 19 && nr.PlatformID == 0 && nr.EncodingID == 5 ) { string sDetails = "name string(" + nr.PlatformID + ", " + nr.EncodingID + ", 0x" + nr.LanguageID.ToString("x4") + ", " + nr.NameID + ", offset=0x" + nr.StringOffset.ToString("x4") + ")"; v.Error( T.name_NoFormat14, E.name_E_NoFormat14, m_tag, sDetails ); bRet = false; bStringOK = false; } } if ( bStringOK ) { string sDetails = "PlatformID=0, EncodingID=5 is for " + "Variation Sequences (Format 14)"; v.Pass(T.name_NoFormat14, P.name_P_NoFormat14, m_tag, sDetails ); } } if (v.PerformTest(T.name_SampleString)) { Table_cmap cmapTable = (Table_cmap)fontOwner.GetTable("cmap"); if (cmapTable != null) { for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID == 19) { if ( nr.PlatformID == 0 && nr.EncodingID == 5 ) { // Unicode platform encoding ID 5 can be // used for encodings in the 'cmap' table // but not for strings in the 'name' table. // It has already been flagged as an error, // so we will just skip it here. break; } Table_cmap.Subtable CmapSubTable = cmapTable.GetSubtable(nr.PlatformID, nr.EncodingID); if (CmapSubTable != null) { bool bStringOk = true; byte[] strbuf = GetEncodedString(nr); for (uint j=0; j<strbuf.Length;) { if (CmapSubTable.MapCharToGlyph(strbuf, j, true) == 0) { string sDetails = "name string(" + nr.PlatformID + ", " + nr.EncodingID + ", 0x" + nr.LanguageID.ToString("x4") + ", " + nr.NameID + "), character at index " + j + " is not mapped"; v.Error(T.name_SampleString, E.name_E_sample, m_tag, sDetails); bStringOk = false; bRet = false; break; } j += CmapSubTable.BytesInChar(strbuf, j); } if (bStringOk) { string sDetails = "name string(" + nr.PlatformID + ", " + nr.EncodingID + ", 0x" + nr.LanguageID.ToString("x4") + ", " + nr.NameID + ")"; v.Pass(T.name_SampleString, P.name_P_sample, m_tag, sDetails); } } } } } } } if (v.PerformTest(T.name_PreferredFamily)) { bool bFound = false; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID == 16) { string sPrefFam = this.GetString(nr.PlatformID, nr.EncodingID, nr.LanguageID, 16); string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID + ", \"" + sPrefFam + "\""; v.Info(T.name_PreferredFamily, I.name_I_Preferred_family_present, m_tag, s); bFound = true; } } } if (!bFound) { v.Info(T.name_PreferredFamily, I.name_I_Preferred_family_not_present, m_tag); } } if (v.PerformTest(T.name_PreferredSubfamily)) { bool bFound = false; for (uint i=0; i<NumberNameRecords; i++) { NameRecord nr = GetNameRecord(i); if (nr != null) { if (nr.NameID == 17) { string sPrefSubfam = this.GetString(nr.PlatformID, nr.EncodingID, nr.LanguageID, 17); string s = "platID = " + nr.PlatformID + ", encID = " + nr.EncodingID + ", langID = " + nr.LanguageID + ", nameID = " + nr.NameID + ", \"" + sPrefSubfam + "\""; v.Info(T.name_PreferredSubfamily, I.name_I_Preferred_subfamily_present, m_tag, s); bFound = true; } } } if (!bFound) { v.Info(T.name_PreferredSubfamily, I.name_I_Preferred_subfamily_not_present, m_tag); } } if (v.PerformTest(T.name_CopyrightConsistent)) { bool bCopyrightOk = true; // get mac roman English Copyright string if present string sMac = GetString(1, 0, 0, 0); // get windows 3,0 English Copyright string if present string sWin3_0 = GetString(3, 0, 1033, 0); // get windows 3,1 English Copyright string if present string sWin3_1 = GetString(3, 1, 1033, 0); // get windows 3,10 English Copyright string if present string sWin3_10 = GetString(3, 10, 1033, 0); // compare strings if (sMac != null) { if (sWin3_0 != null) { if (sWin3_0.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,0)='" + sMac + "', (3,0,1033,0)='" + sWin3_0 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } if (sWin3_1 != null) { if (sWin3_1.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,0)='" + sMac + "', (3,1,1033,0)='" + sWin3_1 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,0)='" + sMac + "', (3,10,1033,0)='" + sWin3_10 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } } if (sWin3_0 != null) { if (sWin3_1 != null) { if (sWin3_1.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,0)='" + sWin3_0 + "', (3,1,1033,0)='" + sWin3_1 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,0)='" + sWin3_0 + "', (3,10,1033,0)='" + sWin3_10 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } } if (sWin3_1 != null) { if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_1) != 0) { string sDetails = "(3,1,1033,0)='" + sWin3_1 + "', (3,10,1033,0)='" + sWin3_10 + "'"; v.Warning(T.name_CopyrightConsistent, W.name_W_CopyrightInconsistent, m_tag, sDetails); bCopyrightOk = false; } } } if (bCopyrightOk) { v.Pass(T.name_CopyrightConsistent, P.name_P_CopyrightConsistent, m_tag); } else { //bRet = false; } } if (v.PerformTest(T.name_TrademarkConsistent)) { bool bTrademarkOk = true; // get mac roman English Trademark string if present string sMac = GetString(1, 0, 0, 7); // get windows 3,0 English Trademark string if present string sWin3_0 = GetString(3, 0, 1033, 7); // get windows 3,1 English Trademark string if present string sWin3_1 = GetString(3, 1, 1033, 7); // get windows 3,10 English Trademark string if present string sWin3_10 = GetString(3, 10, 1033, 7); // compare strings if (sMac != null) { if (sWin3_0 != null) { if (sWin3_0.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,7)='" + sMac + "', (3,0,1033,7)='" + sWin3_0 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } if (sWin3_1 != null) { if (sWin3_1.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,7)='" + sMac + "', (3,1,1033,7)='" + sWin3_1 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,7)='" + sMac + "', (3,10,1033,7)='" + sWin3_10 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } } if (sWin3_0 != null) { if (sWin3_1 != null) { if (sWin3_1.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,7)='" + sWin3_0 + "', (3,1,1033,7)='" + sWin3_1 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,7)='" + sWin3_0 + "', (3,10,1033,7)='" + sWin3_10 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } } if (sWin3_1 != null) { if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_1) != 0) { string sDetails = "(3,1,1033,7)='" + sWin3_1 + "', (3,10,1033,7)='" + sWin3_10 + "'"; v.Warning(T.name_TrademarkConsistent, W.name_W_TrademarkInconsistent, m_tag, sDetails); bTrademarkOk = false; } } } if (bTrademarkOk) { v.Pass(T.name_TrademarkConsistent, P.name_P_TrademarkConsistent, m_tag); } else { //bRet = false; } } if (v.PerformTest(T.name_DescriptionConsistent)) { bool bDescriptionOk = true; // get mac roman English Description string if present string sMac = GetString(1, 0, 0, 10); // get windows 3,0 English Description string if present string sWin3_0 = GetString(3, 0, 1033, 10); // get windows 3,1 English Description string if present string sWin3_1 = GetString(3, 1, 1033, 10); // get windows 3,10 English Description string if present string sWin3_10 = GetString(3, 10, 1033, 10); // compare strings if (sMac != null) { if (sWin3_0 != null) { if (sWin3_0.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,10)='" + sMac + "', (3,0,1033,10)='" + sWin3_0 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } if (sWin3_1 != null) { if (sWin3_1.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,10)='" + sMac + "', (3,1,1033,10)='" + sWin3_1 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sMac) != 0) { string sDetails = "(1,0,0,10)='" + sMac + "', (3,10,1033,10)='" + sWin3_10 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } } if (sWin3_0 != null) { if (sWin3_1 != null) { if (sWin3_1.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,10)='" + sWin3_0 + "', (3,1,1033,10)='" + sWin3_1 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_0) != 0) { string sDetails = "(3,0,1033,10)='" + sWin3_0 + "', (3,10,1033,10)='" + sWin3_10 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } } if (sWin3_1 != null) { if (sWin3_10 != null) { if (sWin3_10.CompareTo(sWin3_1) != 0) { string sDetails = "(3,1,1033,10)='" + sWin3_1 + "', (3,10,1033,10)='" + sWin3_10 + "'"; v.Warning(T.name_DescriptionConsistent, W.name_W_DescriptionInconsistent, m_tag, sDetails); bDescriptionOk = false; } } } if (bDescriptionOk) { v.Pass(T.name_DescriptionConsistent, P.name_P_DescriptionConsistent, m_tag); } else { //bRet = false; } } return bRet; }
public bool Validate() { long StartTicks = DateTime.Now.Ticks; bool bRet = true; m_Validator.OnFileValidationEvent(this, true); for (uint i=0; i<m_nFonts; i++) { // check to see if user canceled validation if (m_Validator.CancelFlag) { bRet = false; break; } m_Validator.OnFontValidationEvent(i, true); OTFontVal f = GetFont(i); if (f != null) { m_Validator.OnFontParsedEvent(f); if(!f.Validate()) bRet = false; } m_Validator.OnFontValidationEvent(i, false); } // build the elapsed time string int nSeconds = (int)((DateTime.Now.Ticks-StartTicks)/(double)10000000); int nHours = nSeconds / 3600; nSeconds = nSeconds - nHours*3600; int nMins = nSeconds / 60; nSeconds = nSeconds - nMins*60; string sTime = nHours.ToString() + ":" + nMins.ToString("d2") + ":" + nSeconds.ToString("d2"); m_Validator.Info(T.T_NULL, I._GEN_I_TotalValTime, null, sTime); //Let's try to validate the DSIG table in a TTC, if it exists if (IsCollection()) { if (m_ttch.version >= 0x00020000 && GetTableManager().GetUnaliasedTableName(m_ttch.DsigTag) == "DSIG") { MBOBuffer buf = this.ReadPaddedBuffer(m_ttch.DsigOffset, m_ttch.DsigLength); OTTable table = GetTableManager().CreateTableObject(m_ttch.DsigTag, buf); DirectoryEntry de = new DirectoryEntry(); de.tag = m_ttch.DsigTag; de.offset = m_ttch.DsigOffset; de.length = m_ttch.DsigLength; OTFontVal fontOwner = new OTFontVal(this); bRet &= ValidateTable(table, m_Validator, de, fontOwner); } else { m_Validator.Warning(T.T_NULL, W._FONT_W_MissingRecommendedTable, null, "DSIG"); } } m_Validator.OnFileValidationEvent(this, false); if (m_Validator.CancelFlag) { m_Validator.ApplicationError(T.T_NULL, E._GEN_E_UserCanceled, null, ""); bRet = false; } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.GSUB_Version)) { if (Version.GetUint() == 0x00010000) { v.Pass(T.GSUB_Version, P.GSUB_P_Version, m_tag); } else { v.Error(T.GSUB_Version, E.GSUB_E_Version, m_tag, "0x" + Version.GetUint().ToString("x8")); } } bool bScriptListOffsetOK = true; bool bFeatureListOffsetOK = true; bool bLookupListOffsetOK = true; if (v.PerformTest(T.GSUB_HeaderOffsets)) { if (ScriptListOffset == 0) { v.Error(T.GSUB_HeaderOffsets, E.GSUB_E_HeaderOffset_0, m_tag, "ScriptListOffset"); bScriptListOffsetOK = false; bRet = false; } else { if (ScriptListOffset > m_bufTable.GetLength()) { v.Error(T.GSUB_HeaderOffsets, E.GSUB_E_HeaderOffset, m_tag, "ScriptListOffset"); bScriptListOffsetOK = false; bRet = false; } } if (FeatureListOffset == 0) { v.Error(T.GSUB_HeaderOffsets, E.GSUB_E_HeaderOffset_0, m_tag, "FeatureListOffset"); bFeatureListOffsetOK = false; bRet = false; } else { if (FeatureListOffset > m_bufTable.GetLength()) { v.Error(T.GSUB_HeaderOffsets, E.GSUB_E_HeaderOffset, m_tag, "FeatureListOffset"); bFeatureListOffsetOK = false; bRet = false; } } if (LookupListOffset == 0) { v.Error(T.GSUB_HeaderOffsets, E.GSUB_E_HeaderOffset_0, m_tag, "LookupListOffset"); bLookupListOffsetOK = false; bRet = false; } else { if (LookupListOffset > m_bufTable.GetLength()) { v.Error(T.GSUB_HeaderOffsets, E.GSUB_E_HeaderOffset, m_tag, "LookupListOffset"); bLookupListOffsetOK = false; bRet = false; } } if (bScriptListOffsetOK == true && bFeatureListOffsetOK == true && bLookupListOffsetOK == true) { v.Pass(T.GSUB_HeaderOffsets, P.GSUB_P_HeaderOffsets, m_tag); } } if (v.PerformTest(T.GSUB_Subtables)) { if (bScriptListOffsetOK) { ScriptListTable_val slt = GetScriptListTable_val(); if (slt != null) { bRet &= slt.Validate(v, "ScriptList", this); } } if (bFeatureListOffsetOK) { FeatureListTable_val flt = GetFeatureListTable_val(); if (flt != null) { bRet &= flt.Validate(v, "FeatureList", this); } } if (bLookupListOffsetOK) { LookupListTable_val llt = GetLookupListTable_val(); if (llt != null) { bRet &= llt.Validate(v, "LookupList", this); } } } return bRet; }
bool Validate_indexSubTable(Validator v, indexSubTable ist, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; if (!Validate_indexSubHeader(v, ist.header, sID, fontOwner)) { bOk = false; } switch (ist.header.indexFormat) { case 1: if (!Validate_indexSubTable_format1(v, (indexSubTable1)ist, ista, sID, fontOwner)) { bOk = false; } break; case 2: if (!Validate_indexSubTable_format2(v, (indexSubTable2)ist, ista, sID, fontOwner)) { bOk = false; } break; case 3: if (!Validate_indexSubTable_format3(v, (indexSubTable3)ist, ista, sID, fontOwner)) { bOk = false; } break; case 4: if (!Validate_indexSubTable_format4(v, (indexSubTable4)ist, ista, sID, fontOwner)) { bOk = false; } break; case 5: if (!Validate_indexSubTable_format5(v, (indexSubTable5)ist, ista, sID, fontOwner)) { bOk = false; } break; default: Debug.Assert(false, "illegal index format", "format = " + ist.header.indexFormat); break; } if (bOk) { v.Pass(T.EBLC_indexSubTables, P.EBLC_P_indexSubTables, m_tag, sID); } return(bOk); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.maxp_TableVersion)) { uint val = TableVersionNumber.GetUint(); Table_CFF CFFTable = (Table_CFF) fontOwner.GetTable("CFF "); Table_glyf glyfTable = (Table_glyf) fontOwner.GetTable("glyf"); if (val == 0x00005000) { if (CFFTable != null && glyfTable == null) { v.Pass(T.maxp_TableVersion, P.maxp_P_VERSION_0_5, m_tag); } else if (CFFTable == null) { v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_0_5_NOCFF, m_tag); bRet = false; } else if (glyfTable != null) { v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_0_5_glyf, m_tag); bRet = false; } } else if (val == 0x00010000) { if (CFFTable == null && glyfTable != null) { v.Pass(T.maxp_TableVersion, P.maxp_P_VERSION_1_0, m_tag); } else if (glyfTable == null) { v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_1_0_NOglyf, m_tag); bRet = false; } else if (CFFTable != null) { v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_1_0_CFF, m_tag); bRet = false; } } else { v.Error(T.maxp_TableVersion, E.maxp_E_VERSION_INVALID, m_tag, "0x"+val.ToString("x8")); bRet = false; } } if (v.PerformTest(T.maxp_TableLength)) { uint val = TableVersionNumber.GetUint(); if (val == 0x00005000) { if (m_bufTable.GetLength() == 6) { v.Pass(T.maxp_TableLength, P.maxp_P_LENGTH_0_5, m_tag); } else { v.Error(T.maxp_TableLength, E.maxp_E_LENGTH_0_5, m_tag, m_bufTable.GetLength().ToString()); bRet = false; } } else if (val == 0x00010000) { if (m_bufTable.GetLength() == 32) { v.Pass(T.maxp_TableLength, P.maxp_P_LENGTH_1_0, m_tag); } else { v.Error(T.maxp_TableLength, E.maxp_E_LENGTH_1_0, m_tag, m_bufTable.GetLength().ToString()); bRet = false; } } } if (v.PerformTest(T.maxp_NumGlyphsMatchLoca)) { if (TableVersionNumber.GetUint() == 0x00010000) { Table_loca locaTable = (Table_loca)fontOwner.GetTable("loca"); if (locaTable != null) { // locaTable.NumEntry returns (-1) on failure if (locaTable.NumEntry(fontOwner) == NumGlyphs+1) { v.Pass(T.maxp_NumGlyphsMatchLoca, P.maxp_P_NumGlyphsMatchLoca, m_tag, "numGlyphs = " + NumGlyphs); } else { v.Error(T.maxp_NumGlyphsMatchLoca, E.maxp_E_NumGlyphsMatchLoca, m_tag, "numGlyphs = " + NumGlyphs); bRet = false; } } else { v.Error(T.maxp_NumGlyphsMatchLoca, E._TEST_E_TableMissing, m_tag, "loca"); bRet = false; } } else { v.Info(T.maxp_NumGlyphsMatchLoca, I._TEST_I_TableVersion, m_tag, "test = maxp_NumGlyphsMatchLoca"); } } if (v.PerformTest(T.maxp_GlyphStats)) { if (TableVersionNumber.GetUint() == 0x00010000) { Table_glyf glyfTable = (Table_glyf) fontOwner.GetTable("glyf"); if (glyfTable == null) { v.Error(T.maxp_GlyphStats, E._TEST_E_TableMissing, m_tag, "glyf"); bRet = false; } else { bool bGlyphStatsOk = true; if (ComputeMaxpStats(glyfTable, fontOwner)) { if (maxPoints != maxPointsCalc) { String sDetails = "maxPoints = " + maxPoints + ", calculated = " + maxPointsCalc; v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails); bRet = false; bGlyphStatsOk = false; } if (maxContours != maxContoursCalc) { String sDetails = "maxContours = " + maxContours + ", calculated = " + maxContoursCalc; v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails); bRet = false; bGlyphStatsOk = false; } if (maxCompositePoints != maxCompositePointsCalc) { String sDetails = "maxCompositePoints = " + maxCompositePoints + ", calculated = " + maxCompositePointsCalc; v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails); bRet = false; bGlyphStatsOk = false; } if (maxCompositeContours != maxCompositeContoursCalc) { String sDetails = "maxCompositeContours = " + maxCompositeContours + ", calculated = " + maxCompositeContoursCalc; v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails); bRet = false; bGlyphStatsOk = false; } // Bug 2168. // Case 1: Same as max size from glyf table. Info. // Case 2: Same as max size from glyf table + // size(fpgm) + size(prep). Info message. // Case 3: Smaller than max size from glyf table. // Error // Case 4: Neither 1 nor 2. Warning. DirectoryEntry dePrep = fontOwner.GetDirectoryEntry("prep" ); uint prepLength = 0; if ( null != dePrep ) { prepLength = dePrep.length; } DirectoryEntry deFpgm = fontOwner.GetDirectoryEntry("fpgm" ); uint fpgmLength = 0; if ( null != deFpgm ) { fpgmLength = deFpgm.length; } if ( maxSizeOfInstructions == maxSizeOfInstructionsCalc ) { // Case 1: String sDetails = "maxSizeOfInstructions=" + maxSizeOfInstructions + ", computed " + "from the glyf table"; v.Info( T.maxp_GlyphStats, I.maxp_I_Calculation_Method1, m_tag, sDetails); } else if ( maxSizeOfInstructions == ( maxSizeOfInstructionsCalc + prepLength + fpgmLength ) ) { // Case 2: String sDetails = "maxp maxSizeOfInstructions is " + maxSizeOfInstructions + ", which is " + "glyf maxSizeOfInstructions (" + maxSizeOfInstructionsCalc + ") + prep size (" + prepLength + ") + fpgm size (" + fpgmLength + ")"; v.Info( T.maxp_GlyphStats, I.maxp_I_Calculation_Method2, m_tag, sDetails); } else if ( maxSizeOfInstructions < maxSizeOfInstructionsCalc ) { // Case 3 String sDetails = "maxp maxSizeOfInstructions is " + maxSizeOfInstructions + ", which is smaller than the " + "size of instuctions (" + maxSizeOfInstructionsCalc + ") found" + " for some glyph in the glyf table."; v.Error( T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails); bRet = false; } else { // Case 4 String sDetails = "glyf maxSizeOfInstructions=" + maxSizeOfInstructionsCalc + ", prep size=" + prepLength + ", fpgm size=" + fpgmLength + ", whereas maxp maxSizeOfInstruction " + "is " + maxSizeOfInstructions; v.Warning(T.maxp_GlyphStats, W.maxp_W_Calculation_Unclear, m_tag, sDetails); bGlyphStatsOk = false; } if (maxComponentElements != maxComponentElementsCalc) { String sDetails = "maxComponentElements = " + maxComponentElements + ", calculated = " + maxComponentElementsCalc; v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails); bRet = false; bGlyphStatsOk = false; } if (maxComponentDepth != maxComponentDepthCalc) { String sDetails = "maxComponentDepth = " + maxComponentDepth + ", calculated = " + maxComponentDepthCalc; v.Error(T.maxp_GlyphStats, E.maxp_E_Calculation, m_tag, sDetails); bRet = false; bGlyphStatsOk = false; } if (bGlyphStatsOk) { v.Pass(T.maxp_GlyphStats, P.maxp_P_Calculation, m_tag); } } else { v.Warning(T.maxp_GlyphStats, W._TEST_W_ErrorInAnotherTable, m_tag, "Errors in the glyf table are preventing validation of maxPoints, maxContours, maxCompositePoints, maxCompositeContours, maxSizeofInstructions, maxComponentElements, and maxComponentDepth"); } } } else { v.Info(T.maxp_GlyphStats, I._TEST_I_TableVersion, m_tag, "test = maxp_GlyphStats"); } } return bRet; }
bool Validate_indexSubTable_format4(Validator v, indexSubTable4 ist4, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); // header has already been validated // validate numGlyphs uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1; if (ist4.numGlyphs > nGlyphsInRange) { string sDetails = "numGlyphs is invalid: " + sID + ", numGlyphs = " + ist4.numGlyphs + ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex + ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // validate code offset pairs uint nEBDTLength = EBDTTable.GetLength(); for (ushort idGlyph = 0; idGlyph < ist4.numGlyphs; idGlyph++) { indexSubTable4.codeOffsetPair cop = ist4.GetCodeOffsetPair(idGlyph); // glyph code if (cop.glyphCode < ista.firstGlyphIndex || cop.glyphCode > ista.lastGlyphIndex) { string sDetails = "glyph code is invalid: " + sID + ", codeOffsetPair[" + idGlyph + "]" + ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex + ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // offset if (cop.offset > nEBDTLength) { string sDetails = "invalid offset: " + sID + ", codeOffsetPair[" + idGlyph + "].offset = " + cop.offset + ", EBDT length = " + nEBDTLength; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } } return(bOk); }
public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; // check the version if (v.PerformTest(T.JSTF_Version)) { if (Version.GetUint() == 0x00010000) { v.Pass(T.JSTF_Version, P.JSTF_P_Version, m_tag); } else { v.Error(T.JSTF_Version, E.JSTF_E_Version, m_tag, "0x" + Version.GetUint().ToString("x8")); bRet = false; } } // check the JstfScriptRecord array length if (v.PerformTest(T.JSTF_JstfScriptRecord_length)) { if ((uint)FieldOffsets.JstfScriptRecords + JstfScriptCount * 6 > m_bufTable.GetLength()) { v.Error(T.JSTF_JstfScriptRecord_length, E.JSTF_E_Array_pastEOT, m_tag, "JstfScriptRecord array"); bRet = false; } } // check that the JstfScriptRecord array is in alphabetical order if (v.PerformTest(T.JSTF_JstfScriptRecord_order)) { if (JstfScriptCount > 1) { for (uint i = 0; i < JstfScriptCount - 1; i++) { JstfScriptRecord jsrCurr = GetJstfScriptRecord_val(i); JstfScriptRecord jsrNext = GetJstfScriptRecord_val(i + 1); if (jsrCurr.JstfScriptTag >= jsrNext.JstfScriptTag) { v.Error(T.JSTF_JstfScriptRecord_order, E.JSTF_E_Array_order, m_tag, "JstfScriptRecord array"); bRet = false; break; } } } } // check each JstfScriptRecord if (v.PerformTest(T.JSTF_JstfScriptRecords)) { for (uint i = 0; i < JstfScriptCount; i++) { JstfScriptRecord_val jsr = GetJstfScriptRecord_val(i); // check the tag if (!jsr.JstfScriptTag.IsValid()) { v.Error(T.JSTF_JstfScriptRecords, E.JSTF_E_tag, m_tag, "JstfScriptRecord[" + i + "]"); bRet = false; } // check the offset if (jsr.JstfScriptOffset > m_bufTable.GetLength()) { v.Error(T.JSTF_JstfScriptRecords, E.JSTF_E_Offset_PastEOT, m_tag, "JstfScriptRecord[" + i + "]"); bRet = false; } // validate the JstfScript table JstfScript_val js = jsr.GetJstfScriptTable_val(); js.Validate(v, "JstfScriptRecord[" + i + "]", this); } } return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.GDEF_Version)) { if (Version.GetUint() == 0x00010000 || Version.GetUint() == 0x00010002 || Version.GetUint() == 0x00010003) { v.Pass(T.GDEF_Version, P.GDEF_P_Version, m_tag, "0x"+ Version.GetUint().ToString("x8")); } else { v.Error(T.GDEF_Version, E.GDEF_E_Version, m_tag, "0x" + Version.GetUint().ToString("x8")); } } if (v.PerformTest(T.GDEF_HeaderOffsets)) { bool bOffsetsOk = true; if (GlyphClassDefOffset != 0) { if (GlyphClassDefOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "GlyphClassDef"); bOffsetsOk = false; bRet = false; } } if (AttachListOffset != 0) { if (AttachListOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "AttachList"); bOffsetsOk = false; bRet = false; } } if (LigCaretListOffset != 0) { if (LigCaretListOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "LigCaretList"); bOffsetsOk = false; bRet = false; } } if (MarkAttachClassDefOffset != 0) { if (MarkAttachClassDefOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "MarkAttachClassDef"); bOffsetsOk = false; bRet = false; } } if (MarkGlyphSetsDefOffset != 0) { if (MarkGlyphSetsDefOffset > m_bufTable.GetLength()) { v.Error(T.GDEF_HeaderOffsets, E.GDEF_E_HeaderOffset, m_tag, "MarkGlyphSetsDef"); bOffsetsOk = false; bRet = false; } } if (bOffsetsOk == true) { v.Pass(T.GDEF_HeaderOffsets, P.GDEF_P_HeaderOffsets, m_tag); } } if (v.PerformTest(T.GDEF_Subtables)) { if (GlyphClassDefOffset != 0) { ClassDefTable_val cdt = GetGlyphClassDefTable_val(); cdt.Validate(v, "GlyphClassDef", this); } if (AttachListOffset != 0) { AttachListTable_val alt = GetAttachListTable_val(); alt.Validate(v, "AttachList", this); } if (LigCaretListOffset != 0) { LigCaretListTable_val lclt = GetLigCaretListTable_val(); lclt.Validate(v, "LigCaretList", this); } if (MarkAttachClassDefOffset != 0) { ClassDefTable_val macdt = GetMarkAttachClassDefTable_val(); macdt.Validate(v, "MarkAttachClassDef", this); } if (MarkGlyphSetsDefOffset != 0) { MarkGlyphSetsDefTable_val mgsdt = GetMarkGlyphSetsDefTable_val(); mgsdt.Validate(v, "MarkGlyphSetsDef", this); } } // TODO: Version 1.3: Item Variation Store table return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.gasp_Version)) { if (version == 0 || version == 1) { v.Pass(T.gasp_Version, P.gasp_P_Version, m_tag, "version = " + version.ToString()); } else { v.Error(T.gasp_Version, E.gasp_E_Version, m_tag, "version = " + version.ToString() + ", unable to continue validation"); return false; } } if (v.PerformTest(T.gasp_rangeGaspBehavior)) { bool bFlagsOk = true; string first_error = null; for (uint i=0; i<numRanges; i++) { GaspRange gr = GetGaspRange(i); if (gr != null) { if ( (version == 0 && gr.rangeGaspBehavior > 0x3) || (version == 1 && gr.rangeGaspBehavior > 0xf)) { bFlagsOk = false; first_error = "version=" + version + ", range #" + i + ", rangeGaspBehavior=0x" + gr.rangeGaspBehavior.ToString("X4"); break; } } } if (bFlagsOk) { v.Pass(T.gasp_rangeGaspBehavior, P.gasp_P_rangeGaspBehavior, m_tag); } else { v.Error(T.gasp_rangeGaspBehavior, E.gasp_E_rangeGaspBehavior, m_tag, first_error); bRet = false; } } if (v.PerformTest(T.gasp_SortOrder)) { bool bSortOk = true; if (numRanges > 1) { GaspRange grCurr = GetGaspRange(0); GaspRange grNext = null; for (uint i=1; i<numRanges; i++) { grNext = GetGaspRange(i); if (grCurr.rangeMaxPPEM >= grNext.rangeMaxPPEM) { bSortOk = false; break; } grCurr = grNext; } } if (bSortOk) { v.Pass(T.gasp_SortOrder, P.gasp_P_SortOrder, m_tag); } else { v.Error(T.gasp_SortOrder, E.gasp_E_SortOrder, m_tag); bRet = false; } } if (v.PerformTest(T.gasp_Sentinel)) { GaspRange gr = GetGaspRange((uint)numRanges-1); if (gr.rangeMaxPPEM == 0xFFFF) { v.Pass(T.gasp_Sentinel, P.gasp_P_Sentinel, m_tag); } else { v.Error(T.gasp_Sentinel, E.gasp_E_Sentinel, m_tag); bRet = false; } } if (v.PerformTest(T.gasp_AdjRangeIdenticalFlags)) { bool bNoAdjIdent = true; if (numRanges > 1) { for (uint i=0; i<numRanges-1; i++) { GaspRange grCurr = GetGaspRange(i); GaspRange grNext = GetGaspRange(i+1); if (grCurr.rangeGaspBehavior == grNext.rangeGaspBehavior) { string sDetails = "rangeGaspBehavior[" + i + "] = " + grCurr.rangeGaspBehavior + ", rangeGaspBehavior[" + (i+1) + "] = " + grNext.rangeGaspBehavior; v.Warning(T.gasp_AdjRangeIdenticalFlags, W.gasp_W_AdjRangeIdenticalFlags, m_tag, sDetails); bNoAdjIdent = false; } } } if (bNoAdjIdent) { v.Pass(T.gasp_AdjRangeIdenticalFlags, P.gasp_P_AdjRangeIdenticalFlags, m_tag); } } return bRet; }
public bool Validate() { long StartTicks = DateTime.UtcNow.Ticks; bool bRet = true; m_Validator.OnFileValidationEvent(this, true); for (uint i = 0; i < m_nFonts; i++) { // check to see if user canceled validation if (m_Validator.CancelFlag) { bRet = false; break; } m_Validator.OnFontValidationEvent(i, true); OTFontVal f = GetFont(i); if (f != null) { m_Validator.OnFontParsedEvent(f); if (!f.Validate()) { bRet = false; } } m_Validator.OnFontValidationEvent(i, false); } // build the elapsed time string int nSeconds = (int)((DateTime.UtcNow.Ticks - StartTicks) / (double)10000000); int nHours = nSeconds / 3600; nSeconds = nSeconds - nHours * 3600; int nMins = nSeconds / 60; nSeconds = nSeconds - nMins * 60; string sTime = nHours.ToString() + ":" + nMins.ToString("d2") + ":" + nSeconds.ToString("d2"); m_Validator.Info(T.T_NULL, I._GEN_I_TotalValTime, null, sTime); //Let's try to validate the DSIG table in a TTC, if it exists if (IsCollection()) { if (m_ttch.version >= 0x00010000 && GetTableManager().GetUnaliasedTableName(m_ttch.DsigTag) == "DSIG") { MBOBuffer buf = this.ReadPaddedBuffer(m_ttch.DsigOffset, m_ttch.DsigLength); OTTable table = GetTableManager().CreateTableObject(m_ttch.DsigTag, buf); DirectoryEntry de = new DirectoryEntry(); de.tag = m_ttch.DsigTag; de.offset = m_ttch.DsigOffset; de.length = m_ttch.DsigLength; OTFontVal fontOwner = new OTFontVal(this); bRet &= ValidateTable(table, m_Validator, de, fontOwner); } else { m_Validator.Warning(T.T_NULL, W._FONT_W_MissingRecommendedTable, null, "DSIG"); } // TODO: check m_ttch.version == 0x00010000/0x00020000 } m_Validator.OnFileValidationEvent(this, false); if (m_Validator.CancelFlag) { m_Validator.ApplicationError(T.T_NULL, E._GEN_E_UserCanceled, null, ""); bRet = false; } return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.BASE_Version)) { if (Version.GetUint() == 0x00010000 || Version.GetUint() == 0x00010001) { v.Pass(T.BASE_Version, P.BASE_P_Version, m_tag); } else { v.Error(T.BASE_Version, E.BASE_E_Version, m_tag, "0x" + Version.GetUint().ToString("x8")); bRet = false; } } if (v.PerformTest(T.BASE_HeaderOffsets)) { if (HorizAxisOffset == 0) { v.Pass(T.BASE_HeaderOffsets, P.BASE_P_HorizAxisOffset_null, m_tag); } else if (HorizAxisOffset < GetLength()) { v.Pass(T.BASE_HeaderOffsets, P.BASE_P_HorizAxisOffset_valid, m_tag); } else { v.Error(T.BASE_HeaderOffsets, E.BASE_E_HorizAxisOffset_OutsideTable, m_tag); bRet = false; } if (VertAxisOffset == 0) { v.Pass(T.BASE_HeaderOffsets, P.BASE_P_VertAxisOffset_null, m_tag); } else if (VertAxisOffset < GetLength()) { v.Pass(T.BASE_HeaderOffsets, P.BASE_P_VertAxisOffset_valid, m_tag); } else { v.Error(T.BASE_HeaderOffsets, E.BASE_E_VertAxisOffset_OutsideTable, m_tag); bRet = false; } } if (v.PerformTest(T.BASE_HorizAxisTable)) { AxisTable_val at = GetHorizAxisTable_val(); if (at != null) { at.Validate(v, "H Axis", this); } } if (v.PerformTest(T.BASE_VertAxisTable)) { AxisTable_val at = GetVertAxisTable_val(); if (at != null) { at.Validate(v, "V Axis", this); } } // TODO: BASE Item Variation Store return(bRet); }
/***************** * protected methods */ /***************** * public methods */ //meant to avoid code repetition (is called from OTFontVal too) public bool ValidateTable(OTTable table, Validator v, DirectoryEntry de, OTFontVal fontOwner) { String tname = GetTableManager().GetUnaliasedTableName(de.tag); bool bRet = true; // verify the checksum value from the directory entry matches the checksum for the table if (!(tname == "DSIG" && IsCollection())) { uint calcChecksum = 0; if (table != null) { calcChecksum = table.CalcChecksum(); } if (de.checkSum != calcChecksum) { string s = "table '" + de.tag + "', calc: 0x" + calcChecksum.ToString("x8") + ", font: 0x" + de.checkSum.ToString("x8"); v.Error(T.T_NULL, E._DE_E_ChecksumError, de.tag, s); bRet = false; } } // verify that table has pad bytes set to zero if (table != null) { uint nBytes = 0; try { nBytes = GetNumPadBytesAfterTable(table); } catch (Exception e) { v.ApplicationError(T.T_NULL, E._Table_E_Exception, de.tag, "GetNumPadBytesAfterTable: " + e.Message); bRet = false; } bool bPadBytesZero = true; if (nBytes != 0) { long PadFilePos = table.GetBuffer().GetFilePos() + table.GetBuffer().GetLength(); byte[] padbuf = ReadBytes(PadFilePos, nBytes); for (int iByte = 0; iByte < padbuf.Length; iByte++) { if (padbuf[iByte] != 0) { bPadBytesZero = false; break; } } } if (bPadBytesZero == false) { v.Warning(T.T_NULL, W._DE_W_PadBytesNotZero, de.tag, "after " + de.tag + " table"); } } // ask the table object to validate its data if (!(tname == "DSIG" && IsCollection())) { v.OnTableValidationEvent(de, true); } if (table != null) { if (v.TestTable(de.tag)) // don't test deselected tables { try { ITableValidate valtable = (ITableValidate)table; bRet &= valtable.Validate(v, fontOwner); } catch (InvalidCastException e) { v.ApplicationError(T.T_NULL, E._Table_E_Exception, table.m_tag, e.ToString()); bRet = false; } } else { v.Info(I._Table_I_NotSelected, de.tag); } } else { if (de.length == 0) { // check if it's a known OT table type since zero length private tables seem allowable if (TableManager.IsKnownOTTableType(de.tag)) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry length is zero"); bRet = false; } } else if (de.offset == 0) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The directory entry offset is zero"); bRet = false; } else if (de.offset > GetFileLength()) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table offset points past end of file"); bRet = false; } else if (de.offset + de.length > GetFileLength()) { v.Error(T.T_NULL, E._Table_E_Invalid, de.tag, "The table extends past end of file"); bRet = false; } else { v.Error(E._Table_E_Invalid, de.tag); bRet = false; } } if (!(tname == "DSIG" && IsCollection())) { v.OnTableValidationEvent(de, false); } return(bRet); }
bool Validate_indexSubTable_format5(Validator v, indexSubTable5 ist5, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); // header has already been validated // validate the image size if (ist5.numGlyphs*ist5.imageSize > EBDTTable.GetLength()) { string sDetails = "images extend past end of EBDT table: " + sID + ", imageSize = " + ist5.imageSize + ", EBDT length = " + EBDTTable.GetLength(); v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // validate the bigGlyphMetrics val_EBDT.bigGlyphMetrics_val bgm = val_EBDT.bigGlyphMetrics_val.CreateFromBigGlyphMetrics(ist5.bigMetrics); bgm.Validate(v, sID, this); // validate numGlyphs uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1; if (ist5.numGlyphs > nGlyphsInRange) { string sDetails = "numGlyphs is invalid: " + sID + ", numGlyphs = " + ist5.numGlyphs + ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex + ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // validate glyphCodeArray for (ushort i=0; i<ist5.numGlyphs; i++) { ushort idGlyph = ist5.GetGlyphCode(i); if (idGlyph < ista.firstGlyphIndex || idGlyph > ista.lastGlyphIndex) { string sDetails = "invalid glyph id: " + sID + ", glyphCodeArray[" + i + "] = " + idGlyph + ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex + ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } } return bOk; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.head_TableLength)) { if (m_bufTable.GetLength() == 54) { v.Pass(T.head_TableLength, P.head_P_TableLength, m_tag); } else { v.Error(T.head_TableLength, E.head_E_TableLength, m_tag, m_bufTable.GetLength().ToString()); bRet = false; } } if (v.PerformTest(T.head_TableVersion)) { if (TableVersionNumber.GetUint() == 0x00010000) { v.Pass(T.head_TableVersion, P.head_P_TableVersion, m_tag); } else { v.Error(T.head_TableVersion, E.head_E_TableVersion, m_tag, "0x"+TableVersionNumber.GetUint().ToString("x8")); bRet = false; } } if (v.PerformTest(T.head_fontRevision)) { string sVersion = fontOwner.GetFontVersion(); if (sVersion != null) { if (sVersion.Length >= 11 && sVersion.StartsWith("Version ") && Char.IsDigit(sVersion, 8)) { string sVersionNum = sVersion.Substring(8); bool bFoundDecPt = false; int nLastDigitPos = 0; for (int i=0; i<sVersionNum.Length; i++) { if (Char.IsDigit(sVersionNum, i)) { nLastDigitPos = i; } else if (sVersionNum[i] == '.') { if (!bFoundDecPt) { bFoundDecPt = true; } else { break; } } else { break; } } double fVersion = Double.Parse(sVersionNum.Substring(0, nLastDigitPos+1)); double fRevision = fontRevision.GetDouble(); if (Math.Round(fVersion, 3) == Math.Round(fRevision, 3)) { v.Pass(T.head_fontRevision, P.head_P_fontRevision, m_tag, fRevision.ToString("f3")); } else { string s = "revision: " + fRevision.ToString("f3") + ", version: " + sVersionNum; v.Warning(T.head_fontRevision, W.head_W_fontRevision, m_tag, s); } } } } if (v.PerformTest(T.head_ChecksumAdjustment)) { if (checkSumAdjustment == 0xb1b0afba - fontOwner.CalcChecksum()) { v.Pass(T.head_ChecksumAdjustment, P.head_P_FontChecksum, m_tag, "0x"+checkSumAdjustment.ToString("x8")); } else { v.Error(T.head_ChecksumAdjustment, E.head_E_FontChecksum, m_tag, "0x"+checkSumAdjustment.ToString("x8")); bRet = false; } } if (v.PerformTest(T.head_MagicNumber)) { if (magicNumber == 0x5f0f3cf5) { v.Pass(T.head_MagicNumber, P.head_P_MagicNumber, m_tag); } else { v.Error(T.head_MagicNumber, E.head_E_MagicNumber, m_tag, "0x"+magicNumber.ToString("x8")); bRet = false; } } if (v.PerformTest(T.head_FlagTests)) { ushort val = flags; // bit 0 indicates baseline for font at y=0 // bit 1 indicates left sidebearing point at x=0 // bit 2 indicates instructions may depend on point size // bit 3 indicates forcing ppem to integer values instead of fractional values // bit 4 indicates non-linear scaling - if set allows presence of LTSH and/or hdmx tables Table_hdmx hdmxTable = (Table_hdmx)fontOwner.GetTable("hdmx"); Table_LTSH LTSHTable = (Table_LTSH)fontOwner.GetTable("LTSH"); if ((val & 0x0010) == 0) { if (hdmxTable == null) { v.Pass(T.head_FlagTests, P.head_P_flags_bit4_0_hdmx, m_tag); } else { v.Error(T.head_FlagTests, E.head_E_flags_bit4_0_hdmx, m_tag); } if (LTSHTable == null) { v.Pass(T.head_FlagTests, P.head_P_flags_bit4_0_LTSH, m_tag); } else { v.Error(T.head_FlagTests, E.head_E_flags_bit4_0_LTSH, m_tag); } } else { if (hdmxTable != null) { v.Pass(T.head_FlagTests, P.head_P_flags_bit4_1_hdmx, m_tag); } else { v.Warning(T.head_FlagTests, W.head_W_flags_bit4_1_hdmx, m_tag); } if (LTSHTable != null) { v.Pass(T.head_FlagTests, P.head_P_flags_bit4_1_LTSH, m_tag); } else { v.Warning(T.head_FlagTests, W.head_W_flags_bit4_1_LTSH, m_tag); } } // bits 5 - 10 are used by apple and ignored by windows // bit 11 indicates font data is 'lossless' as a result of having been compressed/decompressed // bit 12 indicates a converted font // bit 13 indicates optimized for cleartype // bit 14 reserved if ((val & 0x4000) == 0) { v.Pass(T.head_FlagTests, P.head_P_flags_bit14, m_tag); } else { v.Error(T.head_FlagTests, E.head_E_flags_bit14, m_tag, val.ToString()); bRet = false; } // bit 15 reserved if ((val & 0x8000) == 0) { v.Pass(T.head_FlagTests, P.head_P_flags_bit15, m_tag); } else { v.Error(T.head_FlagTests, E.head_E_flags_bit15, m_tag, val.ToString()); bRet = false; } } if (v.PerformTest(T.head_UnitsPerEmValues)) { ushort val = unitsPerEm; bool bInRange = false; if (val < 16) // opentype spec says min value is 16 { v.Error(T.head_UnitsPerEmValues, E.head_E_unitsPerEm_LT16, m_tag, val.ToString()); bRet = false; } else if (val < 64) // apple spec says min value is 64 { v.Warning(T.head_UnitsPerEmValues, W.head_W_unitsPerEM_LT64, m_tag, val.ToString()); } else if (val > 16384) { v.Error(T.head_UnitsPerEmValues, E.head_E_unitsPerEM_GT16384, m_tag, val.ToString()); bRet = false; } else { bInRange = true; } // apple spec says unitsPerEm must be power of two // but don't check if it's a CFF font if (!fontOwner.ContainsPostScriptOutlines()) { bool bPowerOfTwo = false; for (int i=0; i<16; i++) { ushort nPow2 = (ushort)(1<<i); if (val == nPow2) { bPowerOfTwo = true; break; } } if (bPowerOfTwo) { if (bInRange) { v.Pass(T.head_UnitsPerEmValues, P.head_P_unitsPerEm, m_tag, val.ToString()); } } else { v.Warning(T.head_UnitsPerEmValues, W.head_W_unitsPerEm_Pow2, m_tag, val.ToString()); } } } if (v.PerformTest(T.head_Dates)) { DateTime dtBeforeTrueType = new DateTime(1985, 1, 1); if ((created >> 32) == 0) { DateTime dtCreated = this.GetCreatedDateTime(); if (created == 0) { v.Warning(T.head_Dates, W.head_W_created_0, m_tag); } else if (dtCreated < dtBeforeTrueType || dtCreated > DateTime.Now) { string sDetails = "created = " + created + " (" + dtCreated.ToString("f", null) + ")"; v.Warning(T.head_Dates, W.head_W_created_unlikely, m_tag, sDetails); } else { v.Pass(T.head_Dates, P.head_P_created_0, m_tag); } } else { string sDetails = "created = 0x" + created.ToString("x16"); v.Error(T.head_Dates, E.head_E_created_invalid, m_tag, sDetails); bRet = false; } if ((modified >> 32) == 0) { DateTime dtModified = this.GetModifiedDateTime(); if (modified == 0) { v.Warning(T.head_Dates, W.head_W_modified_0, m_tag); } else if (dtModified < dtBeforeTrueType || dtModified > DateTime.Now) { string sDetails = "modified = " + modified + " (" + dtModified.ToString("f", null) + ")"; v.Warning(T.head_Dates, W.head_W_modified_unlikely, m_tag, sDetails); } else { v.Pass(T.head_Dates, P.head_P_modified_0, m_tag); } } else { string sDetails = "modified = 0x" + modified.ToString("x16"); v.Error(T.head_Dates, E.head_E_modified_invalid, m_tag, sDetails); bRet = false; } } if (v.PerformTest(T.head_MinMaxValues)) { if (fontOwner.ContainsTrueTypeOutlines()) { if (xMin > xMax) { v.Error(T.head_MinMaxValues, E.head_E_xMin_GT_xMax, m_tag); bRet = false; } if (yMin > yMax) { v.Error(T.head_MinMaxValues, E.head_E_yMin_GT_yMax, m_tag); bRet = false; } short xMinExpected = 32767; short xMaxExpected = -32768; short yMinExpected = 32767; short yMaxExpected = -32768; Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf"); if (glyfTable != null) { Table_maxp maxp = (Table_maxp)fontOwner.GetTable("maxp"); if (maxp != null) { for (uint i=0; i<fontOwner.GetMaxpNumGlyphs(); i++) { Table_glyf.header h = glyfTable.GetGlyphHeader(i, fontOwner); if (h != null) { if (xMinExpected > h.xMin) xMinExpected = h.xMin; if (xMaxExpected < h.xMax) xMaxExpected = h.xMax; if (yMinExpected > h.yMin) yMinExpected = h.yMin; if (yMaxExpected < h.yMax) yMaxExpected = h.yMax; } } if (xMin == xMinExpected) { String s = "xMin = " + xMin; v.Pass(T.head_MinMaxValues, P.head_P_xMin_glyf, m_tag, s); } else { string s = "actual: " + xMin + ", expected: " + xMinExpected; v.Error(T.head_MinMaxValues, E.head_E_xMin_glyf, m_tag, s); bRet = false; } if (yMin == yMinExpected) { String s = "yMin = " + yMin; v.Pass(T.head_MinMaxValues, P.head_P_yMin_glyf, m_tag, s); } else { string s = "actual: " + yMin + ", expected: " + yMinExpected; v.Error(T.head_MinMaxValues, E.head_E_yMin_glyf, m_tag, s); bRet = false; } if (xMax == xMaxExpected) { String s = "xMax = " + xMax; v.Pass(T.head_MinMaxValues, P.head_P_xMax_glyf, m_tag, s); } else { string s = "actual: " + xMax + ", expected: " + xMaxExpected; v.Error(T.head_MinMaxValues, E.head_E_xMax_glyf, m_tag, s); bRet = false; } if (yMax == yMaxExpected) { String s = "yMax = " + yMax; v.Pass(T.head_MinMaxValues, P.head_P_yMax_glyf, m_tag, s); } else { string s = "actual: " + yMax + ", expected: " + yMaxExpected; v.Error(T.head_MinMaxValues, E.head_E_yMax_glyf, m_tag, s); bRet = false; } } else { v.Error(T.head_MinMaxValues, E._TEST_E_TableMissing, m_tag, "maxp"); } } else { v.Error(T.head_MinMaxValues, E._TEST_E_TableMissing, m_tag, "glyf"); } } else { v.Info(T.head_MinMaxValues, I._TEST_I_NotForCFF, m_tag, "test = head_MinMaxValues"); } } if (v.PerformTest(T.head_MacStyleBits)) { bool bMacBold = ((macStyle & 0x0001) != 0); bool bMacItal = ((macStyle & 0x0002) != 0); // subfamily (style) string Table_name nameTable = (Table_name)fontOwner.GetTable("name"); string sStyle = null; string sStyleLower = null; if (nameTable != null) { sStyle = nameTable.GetStyleString(); if (sStyle != null) { sStyleLower = sStyle.ToLower(); } } if (sStyleLower != null) { if (bMacBold && sStyleLower.IndexOf("bold") == -1) { v.Error(T.head_MacStyleBits, E.head_E_macStyleBold_subfamily, m_tag, "macStyle bold bit is set, but subfamily is " + sStyle); bRet = false; } else if (!bMacBold && sStyleLower.IndexOf("bold") != -1) { v.Error(T.head_MacStyleBits, E.head_E_macStyleBold_subfamily, m_tag, "macStyle bold bit is clear, but subfamily is " + sStyle); bRet = false; } else { v.Pass(T.head_MacStyleBits, P.head_P_macStyleBold_subfamily, m_tag); } if (bMacItal && sStyleLower.IndexOf("italic") == -1 && sStyleLower.IndexOf("oblique") == -1) { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal_subfamily, m_tag, "macStyle italic bit is set, but subfamily is " + sStyle); bRet = false; } else if (!bMacItal && (sStyleLower.IndexOf("italic") != -1 || sStyleLower.IndexOf("oblique") != -1)) { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal_subfamily, m_tag, "macStyle italic bit is clear, but subfamily is " + sStyle); bRet = false; } else { v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_subfamily, m_tag); } } Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2"); if (OS2Table != null) { // fsSelection bool bOS2Bold = ((OS2Table.fsSelection & 0x0020) != 0); bool bOS2Ital = ((OS2Table.fsSelection & 0x0001) != 0); if (bMacBold == bOS2Bold) { v.Pass(T.head_MacStyleBits, P.head_P_macStyleBold_OS2, m_tag); } else if (bMacBold) { v.Error(T.head_MacStyleBits, E.head_E_macStyleBold1_OS2, m_tag); bRet = false; } else { v.Error(T.head_MacStyleBits, E.head_E_macStyleBold0_OS2, m_tag); bRet = false; } if (bMacItal == bOS2Ital) { v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_OS2, m_tag); } else if (bMacItal) { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal1_OS2, m_tag); bRet = false; } else { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal0_OS2, m_tag); bRet = false; } } Table_post postTable = (Table_post)fontOwner.GetTable("post"); if (postTable != null) { bool bPostItal = (postTable.italicAngle.GetUint() != 0); if (bMacItal == bPostItal) { v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_post, m_tag); } else if (bMacItal) { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal1_post, m_tag); bRet = false; } else { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal0_post, m_tag); bRet = false; } } } if (v.PerformTest(T.head_LowestRecSize)) { if (lowestRecPPEM == 0) { v.Error(T.head_LowestRecSize, E.head_E_lowestRecPPEM_zero, m_tag); bRet = false; } else if (lowestRecPPEM >= 1 && lowestRecPPEM <= 6) { v.Warning(T.head_LowestRecSize, W.head_W_lowestRecPPEM_small, m_tag, "lowestRecPPEM = " + lowestRecPPEM.ToString()); } else if (lowestRecPPEM >= 36) { v.Warning(T.head_LowestRecSize, W.head_W_lowestRecPPEM_large, m_tag, "lowestRecPPEM = " + lowestRecPPEM.ToString()); } else { v.Pass(T.head_LowestRecSize, P.head_P_lowestRecPPEM, m_tag); } } if (v.PerformTest(T.head_FontDirectionHint)) { if (fontDirectionHint >= -2 && fontDirectionHint <= 2) { v.Pass(T.head_FontDirectionHint, P.head_P_fontDirectionHint, m_tag, fontDirectionHint.ToString()); } else { v.Error(T.head_FontDirectionHint, E.head_E_fontDirectionHint, m_tag, fontDirectionHint.ToString()); bRet = false; } } if (v.PerformTest(T.head_IndexToLocFormat)) { if (fontOwner.ContainsPostScriptOutlines()) { v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_ignore, m_tag, "indexToLocFormat = " + indexToLocFormat); } else { if (indexToLocFormat == 0 || indexToLocFormat == 1) { v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_range, m_tag, indexToLocFormat.ToString()); } else { v.Error(T.head_IndexToLocFormat, E.head_E_indexToLocFormat_range, m_tag, indexToLocFormat.ToString()); bRet = false; } if (indexToLocFormat == 0 || indexToLocFormat == 1) { Table_loca locaTable = (Table_loca)fontOwner.GetTable("loca"); if (locaTable != null) { Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (maxpTable != null) { uint locaTableElementSize = 0; if (indexToLocFormat == 0) locaTableElementSize = 2; else if (indexToLocFormat == 1) locaTableElementSize = 4; uint CalcLocaLength = (uint)(maxpTable.NumGlyphs + 1) * locaTableElementSize; if (CalcLocaLength == locaTable.GetLength()) { v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_match, m_tag, indexToLocFormat.ToString()); } else { v.Error(T.head_IndexToLocFormat, E.head_E_indexToLocFormat_match, m_tag, indexToLocFormat.ToString()); bRet = false; } } else { v.Error(T.head_IndexToLocFormat, E._TEST_E_TableMissing, m_tag, "maxp"); } } else { v.Error(T.head_IndexToLocFormat, E._TEST_E_TableMissing, m_tag, "loca"); } } } } if (v.PerformTest(T.head_GlyphDataFormat)) { if (glyphDataFormat == 0) { v.Pass(T.head_GlyphDataFormat, P.head_P_glyphDataFormat, m_tag); } else { v.Error(T.head_GlyphDataFormat, E.head_E_glyphDataFormat, m_tag); bRet = false; } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { string sDetails = ""; string [] Apple_Tables = { "acnt", "avar", "bdat", "bhed", "bloc", "bsln", "cmap", "cvar", "cvt ", "EBSC", "fdsc", "feat", "fmtx", "fpgm", "gasp", "glyf", "gvar", "hdmx", "head", "hhea", "hmtx", "hsty", "just", "kern", "lcar", "loca", "maxp", "mort", "morx", "name", "opbd", "OS/2", "post", "prep", "prop", "trak", "vhea", "vmtx", "Zapf" }; string [] VOLT_only_Tables = { "TSIV" }; string [] VOLT_VTT_shared_Tables = { "TSIS", "TSIP", "TSID" }; string [] VTT_only_Tables = { "TSI0", "TSI1", "TSI2", "TSI3", "TSI4", "TSI5", "TSIJ", "TSIB" }; bool bIdentified = false; for (int i = 0; i < Apple_Tables.Length; i++) { if (Apple_Tables[i] == (string)m_tag) { sDetails = "This table type is defined in the Apple TrueType spec."; bIdentified = true; } } if (!bIdentified) { for (int i = 0; i < VOLT_only_Tables.Length; i++) { if (VOLT_only_Tables[i] == (string)m_tag) { sDetails = "This table type is used by the VOLT tool."; bIdentified = true; } } } if (!bIdentified) { for (int i = 0; i < VOLT_VTT_shared_Tables.Length; i++) { if (VOLT_VTT_shared_Tables[i] == (string)m_tag) { sDetails = "This table type is used by the VOLT tool and the VTT tool."; bIdentified = true; } } } if (!bIdentified) { for (int i = 0; i < VTT_only_Tables.Length; i++) { if (VTT_only_Tables[i] == (string)m_tag) { sDetails = "This table type is used by the VTT tool."; bIdentified = true; } } } v.Info(T.T_NULL, I._Table_I_Non_OT_Table, m_tag, sDetails); // Since there is no way to do any validation on unknown tables // always return true return(true); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.hhea_version)) { if (TableVersionNumber.GetUint() == 0x00010000) { v.Pass(T.hhea_version, P.hhea_P_version, m_tag); } else { v.Error(T.hhea_version, E.hhea_E_version, m_tag, "0x" + TableVersionNumber.GetUint().ToString("x8")); bRet = false; } } if (v.PerformTest(T.hhea_AscenderPositive)) { if (Ascender <= 0) { string s = "Ascender = " + Ascender; v.Error(T.hhea_AscenderPositive, E.hhea_E_AscenderPositive, m_tag, s); bRet = false; } else { v.Pass(T.hhea_AscenderPositive, P.hhea_P_AscenderPositive, m_tag); } } if (v.PerformTest(T.hhea_DescenderNegative)) { if (Descender >= 0) { string s = "Descender = " + Descender; v.Error(T.hhea_DescenderNegative, E.hhea_E_DescenderNegative, m_tag, s); bRet = false; } else { v.Pass(T.hhea_DescenderNegative, P.hhea_P_DescenderNegative, m_tag); } } Table_head headTable = (Table_head)fontOwner.GetTable("head"); if (headTable != null) { if (v.PerformTest(T.hhea_Ascender_yMax)) { if (Ascender > headTable.yMax) { string s = "Ascender = " + Ascender + ", head.yMax = " + headTable.yMax; v.Info(T.hhea_Ascender_yMax, I.hhea_I_Ascender_yMax, m_tag, s); // bRet = false; } else { v.Pass(T.hhea_Ascender_yMax, P.hhea_P_Ascender_yMax, m_tag); } } if (v.PerformTest(T.hhea_Descender_yMin)) { if (Descender < headTable.yMin) { string s = "Descender = " + Descender + ", head.yMin = " + headTable.yMin; v.Info(T.hhea_Descender_yMin, I.hhea_I_Descender_yMin, m_tag, s); // bRet = false; } else { v.Pass(T.hhea_Descender_yMin, P.hhea_P_Descender_yMin, m_tag); } } } else { v.Error(T.hhea_Ascender_yMax, E._TEST_E_TableMissing, m_tag, "head"); bRet = false; } if (v.PerformTest(T.hhea_LineGapPositive)) { if (LineGap < 0) { string s = "LineGap = " + LineGap; v.Warning(T.hhea_LineGapPositive, W.hhea_W_LineGapPositive, m_tag, s); //bRet = false; } else { v.Pass(T.hhea_LineGapPositive, P.hhea_P_LineGapPositive, m_tag); } } Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2"); if (OS2Table != null) { if (v.PerformTest(T.hhea_Ascender_usWinAscent)) { if (OS2Table.usWinAscent != Ascender) { string s = "hhea.Ascender = " + Ascender + ", OS/2.usWinAscent = " + OS2Table.usWinAscent; v.Warning(T.hhea_Ascender_usWinAscent, W.hhea_W_Ascender_usWinAscent, m_tag, s); } else { v.Pass(T.hhea_Ascender_usWinAscent, P.hhea_P_Ascender_usWinAscent, m_tag); } } if (v.PerformTest(T.hhea_Descender_usWinDescent)) { if (OS2Table.usWinDescent != (Descender * -1)) { string s = "hhea.Descender = " + Descender + ", OS/2.usWinDescent = " + OS2Table.usWinDescent; v.Warning(T.hhea_Descender_usWinDescent, W.hhea_W_Descender_usWinDescent, m_tag, s); } else { v.Pass(T.hhea_Descender_usWinDescent, P.hhea_P_Descender_usWinDescent, m_tag); } } // Microsoft is recommending that Ascender, Descender and LineGap be in line with OS2.winAscent, OS2.winDescent // and formulated value for LineGap to make sure font displays the same on Apple as it does no Windows. if (v.PerformTest(T.hhea_LineGap_minGap)) { int sMinGap = (OS2Table.usWinAscent + OS2Table.usWinDescent) - (Ascender - Descender); if (LineGap < sMinGap) { string s = "LineGap = " + LineGap + ", recommended = " + sMinGap; v.Warning(T.hhea_LineGap_minGap, W.hhea_W_LineGap_minGap, m_tag, s); //bRet = false; } else { v.Pass(T.hhea_LineGap_minGap, P.hhea_P_LineGap_minGap, m_tag); } } else { v.Error(T.hhea_LineGap_minGap, E._TEST_E_TableMissing, m_tag, "OS/2"); } } else { v.Error(T.hhea_Ascender_usWinAscent, E._TEST_E_TableMissing, m_tag, "OS/2"); v.Error(T.hhea_Descender_usWinDescent, E._TEST_E_TableMissing, m_tag, "OS/2"); v.Error(T.hhea_LineGap_minGap, E._TEST_E_TableMissing, m_tag, "OS/2"); bRet = false; } if (v.PerformTest(T.hhea_MinMax)) { if (fontOwner.ContainsTrueTypeOutlines()) { Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx"); Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf"); Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (hmtxTable == null) { v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "hmtx"); bRet = false; } else if (glyfTable == null) { v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "glyf"); bRet = false; } else if (maxpTable == null) { v.Error(T.hhea_MinMax, E._TEST_E_TableMissing, m_tag, "maxp"); bRet = false; } else { ushort numGlyphs = fontOwner.GetMaxpNumGlyphs(); ushort awMax = 0; short minLSB = 32767; short minRSB = 32767; short xmaxEx = -32768; Table_hmtx.longHorMetric hm = null; for (uint iGlyph = 0; iGlyph < numGlyphs; iGlyph++) { hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner); if (hm == null) { break; } if (awMax < hm.advanceWidth) { awMax = hm.advanceWidth; // We want to give the user feedback to know what glyph id // has the bad width assigned if (awMax > advanceWidthMax) { string s = "glyph ID = " + iGlyph + ", advance width = " + awMax; v.Error(T.hhea_MinMax, E.hhea_E_advanceWidthMax, m_tag, s); bRet = false; } } Table_glyf.header gh = glyfTable.GetGlyphHeader(iGlyph, fontOwner); // calculate for all non-zero contours...this includes composites if (gh != null && gh.numberOfContours != 0) { if (minLSB > hm.lsb) { minLSB = hm.lsb; } short rsb = (short)(hm.advanceWidth - hm.lsb - (gh.xMax - gh.xMin)); if (minRSB > rsb) { minRSB = rsb; } short extent = (short)(hm.lsb + (gh.xMax - gh.xMin)); if (xmaxEx < extent) { xmaxEx = extent; } } } if (hm != null) { if (advanceWidthMax == awMax) { v.Pass(T.hhea_MinMax, P.hhea_P_advanceWidthMax, m_tag); } else { string s = "actual = " + advanceWidthMax + ", calc = " + awMax; v.Error(T.hhea_MinMax, E.hhea_E_advanceWidthMax, m_tag, s); bRet = false; } if (minLeftSideBearing == minLSB) { v.Pass(T.hhea_MinMax, P.hhea_P_minLeftSideBearing, m_tag); } else { string s = "actual = " + minLeftSideBearing + ", calc = " + minLSB; v.Error(T.hhea_MinMax, E.hhea_E_minLeftSideBearing, m_tag, s); bRet = false; } if (minRightSideBearing == minRSB) { v.Pass(T.hhea_MinMax, P.hhea_P_minRightSideBearing, m_tag); } else { string s = "actual = " + minRightSideBearing + ", calc = " + minRSB; v.Error(T.hhea_MinMax, E.hhea_E_minRightSideBearing, m_tag, s); bRet = false; } if (xMaxExtent == xmaxEx) { v.Pass(T.hhea_MinMax, P.hhea_P_xMaxExtent, m_tag); } else { string s = "actual = " + xMaxExtent + ", calc = " + xmaxEx; v.Error(T.hhea_MinMax, E.hhea_E_xMaxExtent, m_tag, s); bRet = false; } } else { v.Warning(T.hhea_MinMax, W.hhea_W_hmtx_invalid, m_tag, "unable to parse hmtx table"); } } } else { v.Info(T.hhea_MinMax, I._TEST_I_NotForCFF, m_tag, "test = hhea_MinMax"); } } if (v.PerformTest(T.hhea_reserved)) { if (reserved1 != 0) { v.Error(T.hhea_reserved, E.hhea_E_reserved1, m_tag, reserved1.ToString()); bRet = false; } else if (reserved2 != 0) { v.Error(T.hhea_reserved, E.hhea_E_reserved2, m_tag, reserved2.ToString()); bRet = false; } else if (reserved3 != 0) { v.Error(T.hhea_reserved, E.hhea_E_reserved3, m_tag, reserved3.ToString()); bRet = false; } else if (reserved4 != 0) { v.Error(T.hhea_reserved, E.hhea_E_reserved4, m_tag, reserved4.ToString()); bRet = false; } else { v.Pass(T.hhea_reserved, P.hhea_P_reserved, m_tag); } } if (v.PerformTest(T.hhea_metricDataFormat)) { if (metricDataFormat == 0) { v.Pass(T.hhea_metricDataFormat, P.hhea_P_metricDataFormat, m_tag); } else { v.Error(T.hhea_metricDataFormat, E.hhea_E_metricDataFormat, m_tag, metricDataFormat.ToString()); bRet = false; } } if (v.PerformTest(T.hhea_numberOfHMetrics)) { Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx"); Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (hmtxTable == null) { v.Error(T.hhea_numberOfHMetrics, E._TEST_E_TableMissing, m_tag, "hmtx"); bRet = false; } else if (maxpTable == null) { v.Error(T.hhea_numberOfHMetrics, E._TEST_E_TableMissing, m_tag, "maxp"); bRet = false; } else { ushort numGlyphs = fontOwner.GetMaxpNumGlyphs(); if (numberOfHMetrics * 4 + (numGlyphs - numberOfHMetrics) * 2 == hmtxTable.GetLength()) { v.Pass(T.hhea_numberOfHMetrics, P.hhea_P_numberOfHMetrics, m_tag); } else { v.Error(T.hhea_numberOfHMetrics, E.hhea_E_numberOfHMetrics, m_tag); bRet = false; } } } if (v.PerformTest(T.hhea_caretSlope)) { bool bSlopeOk = true; Table_post postTable = (Table_post)fontOwner.GetTable("post"); if (postTable != null) { uint ia = postTable.italicAngle.GetUint(); double dItalicAngle = postTable.italicAngle.GetDouble(); if (ia == 0) { if (caretSlopeRun != 0) { v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeRunNonZero_italicAngle, m_tag); bSlopeOk = false; bRet = false; } } else { if (caretSlopeRun == 0) { v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeRunZero_italicAngle, m_tag); bSlopeOk = false; bRet = false; } else { double dActualAngle = 90.0 + postTable.italicAngle.GetDouble(); double dhheaAngle = (Math.Atan2(caretSlopeRise, caretSlopeRun)) * (180.0 / Math.PI); if (Math.Abs(dActualAngle - dhheaAngle) >= 1.0) { string sDetails = "caretSlope Rise:Run = " + caretSlopeRise + ":" + caretSlopeRun + " (" + (dhheaAngle - 90.0) + " degrees)" + ", post.italicAngle = 0x" + ia.ToString("x8") + " (" + postTable.italicAngle.GetDouble() + " degrees)"; v.Error(T.hhea_caretSlope, E.hhea_E_caretSlopeAngle_italicAngle, m_tag, sDetails); bSlopeOk = false; bRet = false; } } } } else { v.Error(T.hhea_caretSlope, E._TEST_E_TableMissing, m_tag, "post table missing, can't compare caret slope to italicAngle"); bSlopeOk = false; bRet = false; } if (bSlopeOk) { v.Pass(T.hhea_caretSlope, P.hhea_P_caretSlopeAngle_italicAngle, m_tag); } } return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; Table_hhea hheaTable = (Table_hhea)fontOwner.GetTable("hhea"); if (hheaTable == null) { v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, hhea table is invalid or missing"); return(false); } Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (maxpTable == null) { v.Error(T.T_NULL, E._TEST_E_TableMissing, m_tag, "Unable to test this table, maxp table is invalid or missing"); return(false); } if (v.PerformTest(T.hmtx_TableSize)) { uint nhm = GetNumberOfHMetrics(fontOwner); uint nlsb = GetNumLeftSideBearingEntries(fontOwner); uint CalcTableLength = nhm * 4 + nlsb * 2; if (CalcTableLength == GetLength()) { v.Pass(T.hmtx_TableSize, P.hmtx_P_TableSize, m_tag); } else { v.Error(T.hmtx_TableSize, E.hmtx_E_TableSize, m_tag); bRet = false; } } if (v.PerformTest(T.hmtx_CheckMetrics)) { bool bMetricsOk = true; for (uint iGlyph = 0; iGlyph < fontOwner.GetMaxpNumGlyphs(); iGlyph++) { longHorMetric hm = this.GetOrMakeHMetric(iGlyph, fontOwner); if (hm != null) { if (hm.lsb > hm.advanceWidth) { v.Warning(T.hmtx_CheckMetrics, W.hmtx_W_CheckMetrics_lsb_gt_adv, m_tag, "glyph# " + iGlyph); bMetricsOk = false; } } else { // unable to fetch this horizontal metric // (probably bad hheaTable.numberOfHMetrics or bad table length) bMetricsOk = false; } } if (bMetricsOk) { v.Pass(T.hmtx_CheckMetrics, P.hmtx_P_CheckMetrics, m_tag); } } return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; bool bNumSizesOkay = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); if (v.PerformTest(T.EBLC_version)) { if (version.GetUint() == 0x00020000) { v.Pass(T.EBLC_version, P.EBLC_P_version, m_tag); } else { v.Error(T.EBLC_version, E.EBLC_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation"); return false; } } if (v.PerformTest(T.EBLC_numSizes)) { if (numSizes < (m_bufTable.GetLength() / 48)) { v.Pass(T.EBLC_numSizes, P.EBLC_P_numSizes, m_tag); } else { v.Error(T.EBLC_numSizes, E.EBLC_E_numSizes, m_tag, "0x" + numSizes.ToString("x8")); bNumSizesOkay = false; bRet = false; } } if (v.PerformTest(T.EBLC_TableDependency)) { if (EBDTTable != null) { v.Pass(T.EBLC_TableDependency, P.EBLC_P_TableDependency, m_tag); } else { v.Error(T.EBLC_TableDependency, E.EBLC_E_TableDependency, m_tag); bRet = false; } } if (v.PerformTest(T.EBLC_indexSubTableArrayOffset) && bNumSizesOkay == true) { bool bOffsetsOk = true; bool bIndicesOk = true; uint SmallestPossibleOffset = 8 + numSizes*48; // sizeof header + sizeof bitmapSizeTAbles for (uint i=0; i<numSizes; i++) { bitmapSizeTable bst = GetBitmapSizeTable(i); // start must be less than or equal to end if ( bst.startGlyphIndex > bst.endGlyphIndex) { string s = "index = " + i + ", start index = " + bst.startGlyphIndex + ", stop index = " + bst.endGlyphIndex; v.Error(T.EBLC_SizeTableIndexOrder, E.EBLC_E_BitmapSizeTableIndexOrder, m_tag, s); bIndicesOk = false; bRet = false; } if ( bst.indexSubTableArrayOffset < SmallestPossibleOffset || bst.indexSubTableArrayOffset + bst.indexTablesSize > GetLength()) { string s = "index = " + i + ", indexSubTableArrayOffset = " + bst.indexSubTableArrayOffset + ", indexTablesSize = " + bst.indexTablesSize; v.Error(T.EBLC_indexSubTableArrayOffset, E.EBLC_E_indexSubTableArrayOffset, m_tag, s); bOffsetsOk = false; bRet = false; } else { indexSubTableArray[] ista = GetIndexSubTableArray(bst); for (uint j=0; j < bst.numberOfIndexSubTables; j++) { // first must be less than or equal to last if ( ista[j].firstGlyphIndex > ista[j].lastGlyphIndex) { } // subtable indices must be within size table range if ( ista[j].firstGlyphIndex < bst.startGlyphIndex || ista[j].lastGlyphIndex > bst.endGlyphIndex) { } } } } if (bOffsetsOk) { v.Pass(T.EBLC_indexSubTableArrayOffset, P.EBLC_P_indexSubTableArrayOffset, m_tag); } if (bIndicesOk) { v.Pass(T.EBLC_SizeTableIndexOrder, P.EBLC_P_BitmapSizeTableIndexOrder, m_tag); } } if (v.PerformTest(T.EBLC_bitDepth) && bNumSizesOkay == true) { bool bBitDepthOk = true; for (uint i=0; i<numSizes; i++) { bitmapSizeTable bst = GetBitmapSizeTable(i); if (bst.bitDepth != 1 && bst.bitDepth != 2 && bst.bitDepth != 4 && bst.bitDepth != 8) { string s = "index = " + i + ", bitDepth = " + bst.bitDepth; v.Error(T.EBLC_bitDepth, E.EBLC_E_bitDepth, m_tag, s); bBitDepthOk = false; bRet = false; } } if (bBitDepthOk) { v.Pass(T.EBLC_bitDepth, P.EBLC_P_bitDepth, m_tag); } } if (v.PerformTest(T.EBLC_indexSubTables) && bNumSizesOkay == true) { for (uint i=0; i<numSizes; i++) { bitmapSizeTable bst = GetBitmapSizeTable(i); string sSize = "bitmapsize[" + i + "], ppemX=" + bst.ppemX + ", ppemY=" + bst.ppemY; indexSubTableArray[] ista = GetIndexSubTableArray(bst); for (uint j=0; j < bst.numberOfIndexSubTables; j++) { indexSubTable ist = bst.GetIndexSubTable(ista[j]); string sID = sSize + ", indexSubTable[" + j + "](fmt " + ist.header.indexFormat + ")"; if (!Validate_indexSubTable(v, ist, ista[j], sID, fontOwner)) { bRet = false; } } } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.EBSC_version)) { if (version.GetUint() == 0x00020000) { v.Pass(T.EBSC_version, P.EBSC_P_version, m_tag); } else { v.Error(T.EBSC_version, E.EBSC_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation"); return false; } } if (v.PerformTest(T.EBSC_TableLength)) { uint CalcLength = 8 + (numSizes * 28); if (CalcLength == GetLength()) { v.Pass(T.EBSC_TableLength, P.EBSC_P_TableLength, m_tag); } else { string s = "actual length = " + GetLength() + ", calculated = " + CalcLength; v.Error(T.EBSC_TableLength, E.EBSC_E_TableLength, m_tag, s); bRet = false; } } if (v.PerformTest(T.EBSC_TableDependency)) { Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC"); Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); if ( EBLCTable != null && EBDTTable != null) { v.Pass(T.EBSC_TableDependency, P.EBSC_P_TableDependency, m_tag); } else { string s = "Missing: "; if (EBLCTable == null) { s = s + "EBLC"; } if (EBDTTable == null) { if (EBLCTable == null) s = s + ", EBDT"; else s = s + "EBDT"; } v.Error(T.EBSC_TableDependency, E.EBSC_E_TableDependency, m_tag, s); bRet = false; } } if (v.PerformTest("EBSC_StrikeSizes")) { Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC"); if (EBLCTable != null) { string s = "Missing strike: "; bool bPass = true; for (uint i = 0; i < numSizes; i++) { bitmapScaleTable bitmapScale = GetBitmapScaleTable(i); if (bitmapScale != null) { bool bFound = false; for (uint n = 0; n < EBLCTable.numSizes; n++) { Table_EBLC.bitmapSizeTable bitmapSize = EBLCTable.GetBitmapSizeTable(n); if (bitmapSize != null) { if ( bitmapScale.substitutePpemX == bitmapSize.ppemX && bitmapScale.substitutePpemY == bitmapSize.ppemY) { bFound = true; break; } } } if (!bFound) { string size = "(PpemX:" + bitmapScale.substitutePpemX + ", PpemY:" + bitmapScale.substitutePpemY + ") "; s = s + size; bPass = false; } } } if (bPass) { v.Pass(T.EBSC_StrikeSizes, P.EBSC_P_StrikeSize, m_tag); } else { v.Error(T.EBSC_StrikeSizes, E.EBSC_E_StrikeSize, m_tag, s); } } else { v.Error(T.EBSC_StrikeSizes, E.EBSC_E_StrikeSizeNoEBLC, m_tag); } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.PCLT_TableLength)) { if (GetLength() == 54) { v.Pass(T.PCLT_TableLength, P.PCLT_P_TableLength, m_tag); } else { v.Error(T.PCLT_TableLength, E.PCLT_E_TableLength, m_tag, GetLength().ToString()); bRet = false; } } if (v.PerformTest(T.PCLT_Version)) { if (Version.GetUint() == 0x00010000) { v.Pass(T.PCLT_Version, P.PCLT_P_Version, m_tag); } else { v.Error(T.PCLT_Version, E.PCLT_E_Version, m_tag, "0x"+Version.GetUint().ToString("x8")); bRet = false; } } if (v.PerformTest(T.PCLT_Pitch)) { Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx"); Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (hmtxTable == null) { v.Error(T.PCLT_Pitch, E._TEST_E_TableMissing, m_tag, "hmtx"); bRet = false; } else if (maxpTable == null) { v.Error(T.PCLT_Pitch, E._TEST_E_TableMissing, m_tag, "maxp"); bRet = false; } else { uint iSpaceGlyph = fontOwner.FastMapUnicodeToGlyphID(' '); if (iSpaceGlyph < fontOwner.GetMaxpNumGlyphs()) { Table_hmtx.longHorMetric hmSpace = hmtxTable.GetOrMakeHMetric(iSpaceGlyph, fontOwner); if (hmSpace != null) { if (Pitch == hmSpace.advanceWidth) { v.Pass(T.PCLT_Pitch, P.PCLT_P_Pitch, m_tag); } else { string s = "actual = " + Pitch + ", expected = " + hmSpace.advanceWidth; v.Error(T.PCLT_Pitch, E.PCLT_E_Pitch, m_tag, s); bRet = false; } } } else { // JJF Figure out what to do v.Warning(T.PCLT_Pitch, W._TEST_W_ErrorInAnotherTable, m_tag, "can't validate Pitch field, error getting the space glyph"); bRet = false; } } } if (v.PerformTest(T.PCLT_Style)) { ushort Posture = (ushort)(Style & 0x0003); ushort Width = (ushort)((Style>>2) & 0x0007); ushort Structure = (ushort)((Style>>5) & 0x001f); ushort Reserved = (ushort)(Style>>10); bool bBitsOk = true; if (Posture == 3) { v.Error(T.PCLT_Style, E.PCLT_E_Style_Posture, m_tag, "0x"+Style.ToString("x4")); bBitsOk = false; bRet = false; } if (Width == 5) { v.Error(T.PCLT_Style, E.PCLT_E_Style_Width, m_tag, "0x"+Style.ToString("x4")); bBitsOk = false; bRet = false; } if (Structure > 17) { v.Error(T.PCLT_Style, E.PCLT_E_Style_Structure, m_tag, "0x"+Style.ToString("x4")); bBitsOk = false; bRet = false; } if (Reserved != 0) { v.Error(T.PCLT_Style, E.PCLT_E_Style_Reserved, m_tag, "0x"+Style.ToString("x4")); bBitsOk = false; bRet = false; } if (bBitsOk) { v.Pass(T.PCLT_Style, P.PCLT_P_Style, m_tag); } } if (v.PerformTest(T.PCLT_StrokeWeight)) { if (StrokeWeight >= -7 && StrokeWeight <= 7) { v.Pass(T.PCLT_StrokeWeight, P.PCLT_P_StrokeWeight, m_tag, StrokeWeight.ToString()); } else { v.Error(T.PCLT_StrokeWeight, E.PCLT_E_StrokeWeight, m_tag, StrokeWeight.ToString()); bRet = false; } } if (v.PerformTest(T.PCLT_WidthType)) { if (WidthType >= -5 && WidthType <= 5) { v.Pass(T.PCLT_WidthType, P.PCLT_P_WidthType, m_tag, WidthType.ToString()); } else { v.Error(T.PCLT_WidthType, E.PCLT_E_WidthType, m_tag, WidthType.ToString()); bRet = false; } } if (v.PerformTest(T.PCLT_SerifStyle)) { uint bot6 = (uint)SerifStyle & 0x3f; uint top2 = (uint)SerifStyle>>6; bool bBitsOk = true; if (bot6 > 12) { v.Error(T.PCLT_SerifStyle, E.PCLT_E_Bottom6, m_tag, "0x"+SerifStyle.ToString("x2")); bBitsOk = false; bRet = false; } if (top2 == 0 || top2 == 3) { v.Error(T.PCLT_SerifStyle, E.PCLT_E_Top2, m_tag); bBitsOk = false; bRet = false; } if (bBitsOk) { v.Pass(T.PCLT_SerifStyle, P.PCLT_P_SerifStyle, m_tag); } } if (v.PerformTest(T.PCLT_Reserved)) { if (Reserved == 0) { v.Pass(T.PCLT_Reserved, P.PCLT_P_Reserved, m_tag); } else { v.Error(T.PCLT_Reserved, E.PCLT_E_Reserved, m_tag, Reserved.ToString()); bRet = false; } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; m_nCachedMaxpNumGlyphs = fontOwner.GetMaxpNumGlyphs(); if (v.PerformTest(T.EBDT_version)) { if (version.GetUint() == 0x00020000) { v.Pass(T.EBDT_version, P.EBDT_P_version, m_tag); } else { v.Error(T.EBDT_version, E.EBDT_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation"); return false; } } if (v.PerformTest(T.EBDT_TableDependency)) { Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC"); if (EBLCTable != null) { v.Pass(T.EBDT_TableDependency, P.EBDT_P_TableDependency, m_tag); } else { v.Error(T.EBDT_TableDependency, E.EBDT_E_TableDependency, m_tag); bRet = false; } } if (v.PerformTest(T.EBDT_GlyphImageData)) { bool bGlyphImageDataOk = true; Table_EBLC EBLCTable = (Table_EBLC)fontOwner.GetTable("EBLC"); // for each bitmap size for (uint i=0; i<EBLCTable.numSizes; i++) { Table_EBLC.bitmapSizeTable bst = EBLCTable.GetBitmapSizeTable(i); string sSize = "bitmapsize[" + i + "], ppemX=" + bst.ppemX + ", ppemY=" + bst.ppemY; Table_EBLC.indexSubTableArray[] ista = EBLCTable.GetIndexSubTableArray(bst); if (ista != null) { for (uint j=0; j < bst.numberOfIndexSubTables; j++) { Table_EBLC.indexSubTable ist = null; if (ista[j] != null) { ist = bst.GetIndexSubTable(ista[j]); } if (ist != null) { string sID = sSize + ", indexSubTable[" + j + "](index fmt " + ist.header.indexFormat + ", image fmt " + ist.header.imageFormat + ")"; switch(ist.header.imageFormat) { case 1: if (!Validate_Format1(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; case 2: if (!Validate_Format2(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; case 3: if (!Validate_Format3(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; case 4: if (!Validate_Format4(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; case 5: if (!Validate_Format5(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; case 6: if (!Validate_Format6(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; case 7: if (!Validate_Format7(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; case 8: if (!Validate_Format8(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; case 9: if (!Validate_Format9(v, sID, ist)) { bGlyphImageDataOk = false; bRet = false; } break; default: break; } } } } } if (bGlyphImageDataOk) { v.Pass(T.EBDT_GlyphImageData, P.EBDT_P_GlyphImageData, m_tag); } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; bool bNumSizesOkay = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); if (v.PerformTest(T.EBLC_version)) { if (version.GetUint() == 0x00020000) { v.Pass(T.EBLC_version, P.EBLC_P_version, m_tag); } else { v.Error(T.EBLC_version, E.EBLC_E_version, m_tag, "version = 0x" + version.GetUint().ToString("x8") + ", unable to continue validation"); return(false); } } if (v.PerformTest(T.EBLC_numSizes)) { if (numSizes < (m_bufTable.GetLength() / 48)) { v.Pass(T.EBLC_numSizes, P.EBLC_P_numSizes, m_tag); } else { v.Error(T.EBLC_numSizes, E.EBLC_E_numSizes, m_tag, "0x" + numSizes.ToString("x8")); bNumSizesOkay = false; bRet = false; } } if (v.PerformTest(T.EBLC_TableDependency)) { if (EBDTTable != null) { v.Pass(T.EBLC_TableDependency, P.EBLC_P_TableDependency, m_tag); } else { v.Error(T.EBLC_TableDependency, E.EBLC_E_TableDependency, m_tag); bRet = false; } } if (v.PerformTest(T.EBLC_indexSubTableArrayOffset) && bNumSizesOkay == true) { bool bOffsetsOk = true; bool bIndicesOk = true; uint SmallestPossibleOffset = 8 + numSizes * 48; // sizeof header + sizeof bitmapSizeTAbles for (uint i = 0; i < numSizes; i++) { bitmapSizeTable bst = GetBitmapSizeTable(i); // start must be less than or equal to end if (bst.startGlyphIndex > bst.endGlyphIndex) { string s = "index = " + i + ", start index = " + bst.startGlyphIndex + ", stop index = " + bst.endGlyphIndex; v.Error(T.EBLC_SizeTableIndexOrder, E.EBLC_E_BitmapSizeTableIndexOrder, m_tag, s); bIndicesOk = false; bRet = false; } if (bst.indexSubTableArrayOffset < SmallestPossibleOffset || bst.indexSubTableArrayOffset + bst.indexTablesSize > GetLength()) { string s = "index = " + i + ", indexSubTableArrayOffset = " + bst.indexSubTableArrayOffset + ", indexTablesSize = " + bst.indexTablesSize; v.Error(T.EBLC_indexSubTableArrayOffset, E.EBLC_E_indexSubTableArrayOffset, m_tag, s); bOffsetsOk = false; bRet = false; } else { indexSubTableArray[] ista = GetIndexSubTableArray(bst); for (uint j = 0; j < bst.numberOfIndexSubTables; j++) { // first must be less than or equal to last if (ista[j].firstGlyphIndex > ista[j].lastGlyphIndex) { } // subtable indices must be within size table range if (ista[j].firstGlyphIndex <bst.startGlyphIndex || ista[j].lastGlyphIndex> bst.endGlyphIndex) { } } } } if (bOffsetsOk) { v.Pass(T.EBLC_indexSubTableArrayOffset, P.EBLC_P_indexSubTableArrayOffset, m_tag); } if (bIndicesOk) { v.Pass(T.EBLC_SizeTableIndexOrder, P.EBLC_P_BitmapSizeTableIndexOrder, m_tag); } } if (v.PerformTest(T.EBLC_bitDepth) && bNumSizesOkay == true) { bool bBitDepthOk = true; for (uint i = 0; i < numSizes; i++) { bitmapSizeTable bst = GetBitmapSizeTable(i); if (bst.bitDepth != 1 && bst.bitDepth != 2 && bst.bitDepth != 4 && bst.bitDepth != 8) { string s = "index = " + i + ", bitDepth = " + bst.bitDepth; v.Error(T.EBLC_bitDepth, E.EBLC_E_bitDepth, m_tag, s); bBitDepthOk = false; bRet = false; } } if (bBitDepthOk) { v.Pass(T.EBLC_bitDepth, P.EBLC_P_bitDepth, m_tag); } } if (v.PerformTest(T.EBLC_indexSubTables) && bNumSizesOkay == true) { for (uint i = 0; i < numSizes; i++) { bitmapSizeTable bst = GetBitmapSizeTable(i); string sSize = "bitmapsize[" + i + "], ppemX=" + bst.ppemX + ", ppemY=" + bst.ppemY; indexSubTableArray[] ista = GetIndexSubTableArray(bst); for (uint j = 0; j < bst.numberOfIndexSubTables; j++) { indexSubTable ist = bst.GetIndexSubTable(ista[j]); string sID = sSize + ", indexSubTable[" + j + "](fmt " + ist.header.indexFormat + ")"; if (!Validate_indexSubTable(v, ist, ista[j], sID, fontOwner)) { bRet = false; } } } } return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.DSIG_Formats)) { bool bFormatsOk = true; for (uint i = 0; i < usNumSigs; i++) { SigFormatOffset sfo; try { sfo = GetSigFormatOffset(i); if (sfo.ulFormat != 1) { v.Error(T.DSIG_Formats, E.DSIG_E_Formats, m_tag, "block " + i + ", format = " + sfo.ulFormat); bFormatsOk = false; bRet = false; } } catch (IndexOutOfRangeException e) { v.Error(T.DSIG_Formats, E.DSIG_E_Formats, m_tag, "block " + i + ", " + e); bFormatsOk = false; bRet = false; break; // No point continuing } } if (bFormatsOk) { v.Pass(T.DSIG_Formats, P.DSIG_P_Formats, m_tag); } } if (v.PerformTest(T.DSIG_Reserved)) { bool bReservedOk = true; for (uint i = 0; i < usNumSigs; i++) { SignatureBlock sb; try { sb = GetSignatureBlock(i); if (sb.usReserved1 != 0 || sb.usReserved2 != 0) { v.Error(T.DSIG_Reserved, E.DSIG_E_Reserved, m_tag, "block " + i); bReservedOk = false; bRet = false; } } catch (IndexOutOfRangeException) { v.Error(T.DSIG_Reserved, E.DSIG_E_Reserved, m_tag, "block " + i); bReservedOk = false; bRet = false; break; // No point continuing } } if (bReservedOk) { v.Pass(T.DSIG_Reserved, P.DSIG_P_Reserved, m_tag); } } if (v.PerformTest(T.DSIG_VerifySignature)) { OTFile file = fontOwner.GetFile(); System.IO.FileStream fs = file.GetFileStream(); String sFilename = fs.Name; try { WinVerifyTrustWrapper wvt = new WinVerifyTrustWrapper(); if (wvt.WinVerifyTrustFile(sFilename)) { if (wvt.usNumSigs > 0) { if (wvt.Warn_TTCv1 || wvt.Warn_DSIG_in_memFonts) { v.Warning(T.DSIG_VerifySignature, W.DSIG_W_VerifySignature_Generic, m_tag, (wvt.Warn_TTCv1 ? "TTC with v1 header;":"") + (wvt.Warn_DSIG_in_memFonts ? "DSIG tables detected in member fonts;":"")); } v.Pass(T.DSIG_VerifySignature, P.DSIG_P_VerifySignature, m_tag, wvt.Signer); } else { v.Pass(T.DSIG_VerifySignature, P.DSIG_P_VerifySignature, m_tag); } } else { v.Error(T.DSIG_VerifySignature, E.DSIG_E_VerifySignature, m_tag); bRet = false; } } catch (Exception e) { if (e is NotImplementedException) { v.ApplicationError(T.DSIG_VerifySignature, E.DSIG_A_UNUSUAL_TTC_TABLE_LAYOUT, m_tag, e.Message); } else { v.Error(T.DSIG_VerifySignature, E.DSIG_E_VerifySignature, m_tag, e.Message); } bRet = false; } } return(bRet); }
bool Validate_indexSubTable_format3(Validator v, indexSubTable3 ist3, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); // header has already been validated // validate the array of offsets int nArrSize = ista.lastGlyphIndex - ista.firstGlyphIndex + 1; uint nEBDTLength = EBDTTable.GetLength(); for (ushort i = 0; i < nArrSize; i++) { uint offsetImage = ist3.GetOffset(i) + ist3.header.imageDataOffset; if (offsetImage > nEBDTLength) { string sDetails = "invalid offset: " + sID + ", offset[" + i + "] = " + offsetImage + ", EBDT length = " + nEBDTLength; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } } return(bOk); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; ushort numGlyphs = GetNumGlyphs(fontOwner); if (v.PerformTest(T.hdmx_Version)) { if (TableVersionNumber == 0) { v.Pass(T.hdmx_Version, P.hdmx_P_Version, m_tag); } else { v.Error(T.hdmx_Version, E.hdmx_E_Version, m_tag, TableVersionNumber.ToString()); bRet = false; } } bool bNumDeviceRecordsOk = true; if (v.PerformTest(T.hdmx_NumDeviceRecords)) { if (NumberDeviceRecords >= 0) { v.Pass(T.hdmx_NumDeviceRecords, P.hdmx_P_NumDeviceRecords, m_tag, NumberDeviceRecords.ToString()); } else { v.Error(T.hdmx_NumDeviceRecords, E.hdmx_E_NumDeviceRecords_neg, m_tag, NumberDeviceRecords.ToString()); bNumDeviceRecordsOk = false; bRet = false; } } bool bSizeOk = true; if (v.PerformTest(T.hdmx_SizeofDeviceRecord)) { if ((SizeofDeviceRecord & 3) != 0) { v.Error(T.hdmx_SizeofDeviceRecord, E.hdmx_E_SizeofDeviceRecord_alignment, m_tag, SizeofDeviceRecord.ToString()); bSizeOk = false; bRet = false; } uint CalculatedSizeofDeviceRecord = CalculateSizeofDeviceRecord(numGlyphs); if (SizeofDeviceRecord != CalculatedSizeofDeviceRecord) { string s = "actual = " + SizeofDeviceRecord + ", calc = " + CalculatedSizeofDeviceRecord; v.Error(T.hdmx_SizeofDeviceRecord, E.hdmx_E_SizeofDeviceRecord_numGlyphs, m_tag, s); bSizeOk = false; bRet = false; } if (bSizeOk) { v.Pass(T.hdmx_SizeofDeviceRecord, P.hdmx_P_SizeofDeviceRecord, m_tag, SizeofDeviceRecord.ToString()); } } bool bLengthOk = true; if (v.PerformTest(T.hdmx_TableLength)) { if (bNumDeviceRecordsOk) { uint CalculatedTableLength = 8 + (uint)NumberDeviceRecords * CalculateSizeofDeviceRecord(numGlyphs); if (GetLength() == CalculatedTableLength) { v.Pass(T.hdmx_TableLength, P.hdmx_P_TableLength, m_tag); } else { string s = "actual: " + GetLength() + ", calc: " + CalculatedTableLength; v.Error(T.hdmx_TableLength, E.hdmx_E_TableLength, m_tag, s); bLengthOk = false; bRet = false; } } else { v.Warning(T.hdmx_TableLength, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate table length"); } } if (v.PerformTest(T.hdmx_DeviceRecordPadBytesZero)) { if (bSizeOk && bLengthOk & bNumDeviceRecordsOk) { uint unpaddedLength = (uint)numGlyphs + 2; if ((unpaddedLength & 3) == 0) { v.Pass(T.hdmx_DeviceRecordPadBytesZero, P.hdmx_P_DeviceRecordPadBytes_none, m_tag); } else { bool bPadOk = true; if (NumberDeviceRecords > 1) { for (uint i=0; i<NumberDeviceRecords; i++) { DeviceRecord dr = GetDeviceRecord(i, numGlyphs); for (uint j=0; j<dr.GetNumPadBytes(); j++) { if (dr.GetPadByte(j) != 0) { bPadOk = false; break; } } } } if (bPadOk) { v.Pass(T.hdmx_DeviceRecordPadBytesZero, P.hdmx_P_DeviceRecordPadBytes_zero, m_tag); } else { v.Error(T.hdmx_DeviceRecordPadBytesZero, E.hdmx_E_DeviceRecordPadBytes_nonzero, m_tag); bRet = false; } } } else { v.Warning(T.hdmx_DeviceRecordPadBytesZero, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate that device record padding bytes are zero"); } } if (v.PerformTest(T.hdmx_SortedOrder)) { if (bSizeOk && bLengthOk && bNumDeviceRecordsOk) { bool bSortOk = true; if (NumberDeviceRecords > 1) { DeviceRecord drCurr = GetDeviceRecord(0, numGlyphs); DeviceRecord drNext = null; for (uint i=1; i<NumberDeviceRecords; i++) { drNext = GetDeviceRecord(i, numGlyphs); if (drCurr.PixelSize >= drNext.PixelSize) { bSortOk = false; break; } drCurr = drNext; } } if (bSortOk) { v.Pass(T.hdmx_SortedOrder, P.hdmx_P_SortedOrder, m_tag); } else { v.Error(T.hdmx_SortedOrder, E.hdmx_E_SortedOrder, m_tag); bRet = false; } } else { v.Warning(T.hdmx_SortedOrder, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate that device records are in sorted order"); } } if (v.PerformTest(T.hdmx_DuplicateDeviceRecords)) { if (bSizeOk && bLengthOk && bNumDeviceRecordsOk) { bool bNoDup = true; if (NumberDeviceRecords > 1) { for (uint i=0; i<NumberDeviceRecords-1; i++) { DeviceRecord dr1 = GetDeviceRecord(i, numGlyphs); for (uint j=i+1; j<NumberDeviceRecords; j++) { DeviceRecord dr2 = GetDeviceRecord(j, numGlyphs); if (dr1.PixelSize == dr2.PixelSize) { bNoDup = false; break; } } } } if (bNoDup) { v.Pass(T.hdmx_DuplicateDeviceRecords, P.hdmx_P_DuplicateDeviceRecords, m_tag); } else { v.Error(T.hdmx_DuplicateDeviceRecords, E.hdmx_E_DuplicateDeviceRecords, m_tag); bRet = false; } } else { v.Warning(T.hdmx_DuplicateDeviceRecords, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate that there are no duplicate device records"); } } if (v.PerformTest(T.hdmx_Widths)) { if (bSizeOk && bLengthOk && bNumDeviceRecordsOk) { bool bWidthsOk = true; RasterInterf.DevMetricsData dmd = null; try { Version ver = fontOwner.GetFile().GetRasterizer().FTVersion; if ( ver.CompareTo(new Version(2,6,1)) < 0 ) v.Warning(T.hdmx_Widths, W.hdmx_W_Need_Newer_FreeType, m_tag, "Using FreeType Version " + ver + " may not get correct results for HDMX"); dmd = fontOwner.GetCalculatedDevMetrics(); } catch (Exception e) { v.ApplicationError(T.hdmx_Widths, E._Table_E_Exception, m_tag, e.Message); bRet = false; } if (dmd != null) { for (uint i=0; i<NumberDeviceRecords; i++) { DeviceRecord dr = GetDeviceRecord(i, numGlyphs); for (uint iGlyph=0; iGlyph<numGlyphs; iGlyph++) { if (dr.GetWidth(iGlyph) != dmd.hdmxData.Records[i].Widths[iGlyph]) { String sDetails = "rec " + i + ", PixelSize " + dr.PixelSize + ", glyph# " + iGlyph + ", width = " + dr.GetWidth(iGlyph) + ", calc = " + dmd.hdmxData.Records[i].Widths[iGlyph]; v.Error(T.hdmx_Widths, E.hdmx_E_Widths, m_tag, sDetails); bWidthsOk = false; bRet = false; } } } if (bWidthsOk) { v.Pass(T.hdmx_Widths, P.hdmx_P_Widths, m_tag); } } else { // if user didn't cancel, then check for error message if (!v.CancelFlag) { String sDetails = null; try { sDetails = fontOwner.GetDevMetricsDataError(); } catch (Exception e) { v.ApplicationError(T.hdmx_Widths, E._Table_E_Exception, m_tag, e.Message); } Debug.Assert(sDetails != null); v.Error(T.hdmx_Widths, E.hdmx_E_Rasterizer, m_tag, sDetails); bRet = false; } } } else { v.Warning(T.hdmx_Widths, W._TEST_W_OtherErrorsInTable, m_tag, "unable to validate that the widths are correct"); } } return bRet; }
bool Validate_indexSubTable_format5(Validator v, indexSubTable5 ist5, indexSubTableArray ista, string sID, OTFontVal fontOwner) { bool bOk = true; Table_EBDT EBDTTable = (Table_EBDT)fontOwner.GetTable("EBDT"); // header has already been validated // validate the image size if (ist5.numGlyphs * ist5.imageSize > EBDTTable.GetLength()) { string sDetails = "images extend past end of EBDT table: " + sID + ", imageSize = " + ist5.imageSize + ", EBDT length = " + EBDTTable.GetLength(); v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // validate the bigGlyphMetrics val_EBDT.bigGlyphMetrics_val bgm = val_EBDT.bigGlyphMetrics_val.CreateFromBigGlyphMetrics(ist5.bigMetrics); bgm.Validate(v, sID, this); // validate numGlyphs uint nGlyphsInRange = (uint)ista.lastGlyphIndex - ista.firstGlyphIndex + 1; if (ist5.numGlyphs > nGlyphsInRange) { string sDetails = "numGlyphs is invalid: " + sID + ", numGlyphs = " + ist5.numGlyphs + ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex + ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } // validate glyphCodeArray for (ushort i = 0; i < ist5.numGlyphs; i++) { ushort idGlyph = ist5.GetGlyphCode(i); if (idGlyph < ista.firstGlyphIndex || idGlyph > ista.lastGlyphIndex) { string sDetails = "invalid glyph id: " + sID + ", glyphCodeArray[" + i + "] = " + idGlyph + ", indexSubTableArray.firstGlyphIndex = " + ista.firstGlyphIndex + ", indexSubTableArray.lastGlyphIndex = " + ista.lastGlyphIndex; v.Error(T.EBLC_indexSubTables, E.EBLC_E_indexSubTables, m_tag, sDetails); bOk = false; } } return(bOk); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.head_TableLength)) { if (m_bufTable.GetLength() == 54) { v.Pass(T.head_TableLength, P.head_P_TableLength, m_tag); } else { v.Error(T.head_TableLength, E.head_E_TableLength, m_tag, m_bufTable.GetLength().ToString()); bRet = false; } } if (v.PerformTest(T.head_TableVersion)) { if (TableVersionNumber.GetUint() == 0x00010000) { v.Pass(T.head_TableVersion, P.head_P_TableVersion, m_tag); } else { v.Error(T.head_TableVersion, E.head_E_TableVersion, m_tag, "0x" + TableVersionNumber.GetUint().ToString("x8")); bRet = false; } } if (v.PerformTest(T.head_fontRevision)) { string sVersion = fontOwner.GetFontVersion(); if (sVersion != null) { if (sVersion.Length >= 11 && sVersion.StartsWith("Version ") && Char.IsDigit(sVersion, 8)) { string sVersionNum = sVersion.Substring(8); bool bFoundDecPt = false; int nLastDigitPos = 0; for (int i = 0; i < sVersionNum.Length; i++) { if (Char.IsDigit(sVersionNum, i)) { nLastDigitPos = i; } else if (sVersionNum[i] == '.') { if (!bFoundDecPt) { bFoundDecPt = true; } else { break; } } else { break; } } double fVersion = Double.Parse(sVersionNum.Substring(0, nLastDigitPos + 1)); double fRevision = fontRevision.GetDouble(); if (Math.Round(fVersion, 3) == Math.Round(fRevision, 3)) { v.Pass(T.head_fontRevision, P.head_P_fontRevision, m_tag, fRevision.ToString("f3")); } else { string s = "revision: " + fRevision.ToString("f3") + ", version: " + sVersionNum; v.Warning(T.head_fontRevision, W.head_W_fontRevision, m_tag, s); } } } } if (v.PerformTest(T.head_ChecksumAdjustment)) { if (checkSumAdjustment == 0xb1b0afba - fontOwner.CalcChecksum()) { v.Pass(T.head_ChecksumAdjustment, P.head_P_FontChecksum, m_tag, "0x" + checkSumAdjustment.ToString("x8")); } else { v.Error(T.head_ChecksumAdjustment, E.head_E_FontChecksum, m_tag, "0x" + checkSumAdjustment.ToString("x8")); bRet = false; } } if (v.PerformTest(T.head_MagicNumber)) { if (magicNumber == 0x5f0f3cf5) { v.Pass(T.head_MagicNumber, P.head_P_MagicNumber, m_tag); } else { v.Error(T.head_MagicNumber, E.head_E_MagicNumber, m_tag, "0x" + magicNumber.ToString("x8")); bRet = false; } } if (v.PerformTest(T.head_FlagTests)) { ushort val = flags; // bit 0 indicates baseline for font at y=0 // bit 1 indicates left sidebearing point at x=0 // bit 2 indicates instructions may depend on point size // bit 3 indicates forcing ppem to integer values instead of fractional values // bit 4 indicates non-linear scaling - if set allows presence of LTSH and/or hdmx tables Table_hdmx hdmxTable = (Table_hdmx)fontOwner.GetTable("hdmx"); Table_LTSH LTSHTable = (Table_LTSH)fontOwner.GetTable("LTSH"); if ((val & 0x0010) == 0) { if (hdmxTable == null) { v.Pass(T.head_FlagTests, P.head_P_flags_bit4_0_hdmx, m_tag); } else { v.Error(T.head_FlagTests, E.head_E_flags_bit4_0_hdmx, m_tag); } if (LTSHTable == null) { v.Pass(T.head_FlagTests, P.head_P_flags_bit4_0_LTSH, m_tag); } else { v.Error(T.head_FlagTests, E.head_E_flags_bit4_0_LTSH, m_tag); } } else { if (hdmxTable != null) { v.Pass(T.head_FlagTests, P.head_P_flags_bit4_1_hdmx, m_tag); } else { v.Warning(T.head_FlagTests, W.head_W_flags_bit4_1_hdmx, m_tag); } if (LTSHTable != null) { v.Pass(T.head_FlagTests, P.head_P_flags_bit4_1_LTSH, m_tag); } else { v.Warning(T.head_FlagTests, W.head_W_flags_bit4_1_LTSH, m_tag); } } // bits 5 - 10 are used by apple and ignored by windows // bit 11 indicates font data is 'lossless' as a result of having been compressed/decompressed // bit 12 indicates a converted font // bit 13 indicates optimized for cleartype // bit 14 reserved if ((val & 0x4000) == 0) { v.Pass(T.head_FlagTests, P.head_P_flags_bit14, m_tag); } else { v.Error(T.head_FlagTests, E.head_E_flags_bit14, m_tag, val.ToString()); bRet = false; } // bit 15 reserved if ((val & 0x8000) == 0) { v.Pass(T.head_FlagTests, P.head_P_flags_bit15, m_tag); } else { v.Error(T.head_FlagTests, E.head_E_flags_bit15, m_tag, val.ToString()); bRet = false; } } if (v.PerformTest(T.head_UnitsPerEmValues)) { ushort val = unitsPerEm; bool bInRange = false; if (val < 16) // opentype spec says min value is 16 { v.Error(T.head_UnitsPerEmValues, E.head_E_unitsPerEm_LT16, m_tag, val.ToString()); bRet = false; } else if (val < 64) // apple spec says min value is 64 { v.Warning(T.head_UnitsPerEmValues, W.head_W_unitsPerEM_LT64, m_tag, val.ToString()); } else if (val > 16384) { v.Error(T.head_UnitsPerEmValues, E.head_E_unitsPerEM_GT16384, m_tag, val.ToString()); bRet = false; } else { bInRange = true; } // apple spec says unitsPerEm must be power of two // but don't check if it's a CFF font if (!fontOwner.ContainsPostScriptOutlines()) { bool bPowerOfTwo = false; for (int i = 0; i < 16; i++) { ushort nPow2 = (ushort)(1 << i); if (val == nPow2) { bPowerOfTwo = true; break; } } if (bPowerOfTwo) { if (bInRange) { v.Pass(T.head_UnitsPerEmValues, P.head_P_unitsPerEm, m_tag, val.ToString()); } } else { v.Warning(T.head_UnitsPerEmValues, W.head_W_unitsPerEm_Pow2, m_tag, val.ToString()); } } } if (v.PerformTest(T.head_Dates)) { DateTime dtBeforeTrueType = new DateTime(1985, 1, 1); if ((created >> 32) == 0) { DateTime dtCreated = this.GetCreatedDateTime(); string sDetails = "created = " + created + " (" + dtCreated.ToString("f", null) + ")"; if (created == 0) { v.Warning(T.head_Dates, W.head_W_created_0, m_tag); } else if (dtCreated < dtBeforeTrueType || dtCreated > DateTime.Now) { v.Warning(T.head_Dates, W.head_W_created_unlikely, m_tag, sDetails); } else { v.Pass(T.head_Dates, P.head_P_created_0, m_tag, sDetails); } } else { string sDetails = "created = 0x" + created.ToString("x16"); v.Error(T.head_Dates, E.head_E_created_invalid, m_tag, sDetails); bRet = false; } if ((modified >> 32) == 0) { DateTime dtModified = this.GetModifiedDateTime(); string sDetails = "modified = " + modified + " (" + dtModified.ToString("f", null) + ")"; if (modified == 0) { v.Warning(T.head_Dates, W.head_W_modified_0, m_tag); } else if (dtModified < dtBeforeTrueType || dtModified > DateTime.Now) { v.Warning(T.head_Dates, W.head_W_modified_unlikely, m_tag, sDetails); } else { v.Pass(T.head_Dates, P.head_P_modified_0, m_tag, sDetails); } } else { string sDetails = "modified = 0x" + modified.ToString("x16"); v.Error(T.head_Dates, E.head_E_modified_invalid, m_tag, sDetails); bRet = false; } } if (v.PerformTest(T.head_MinMaxValues)) { if (fontOwner.ContainsTrueTypeOutlines()) { if (xMin > xMax) { v.Error(T.head_MinMaxValues, E.head_E_xMin_GT_xMax, m_tag); bRet = false; } if (yMin > yMax) { v.Error(T.head_MinMaxValues, E.head_E_yMin_GT_yMax, m_tag); bRet = false; } short xMinExpected = 32767; short xMaxExpected = -32768; short yMinExpected = 32767; short yMaxExpected = -32768; Table_glyf glyfTable = (Table_glyf)fontOwner.GetTable("glyf"); if (glyfTable != null) { Table_maxp maxp = (Table_maxp)fontOwner.GetTable("maxp"); if (maxp != null) { for (uint i = 0; i < fontOwner.GetMaxpNumGlyphs(); i++) { Table_glyf.header h = glyfTable.GetGlyphHeader(i, fontOwner); if (h != null) { if (xMinExpected > h.xMin) { xMinExpected = h.xMin; } if (xMaxExpected < h.xMax) { xMaxExpected = h.xMax; } if (yMinExpected > h.yMin) { yMinExpected = h.yMin; } if (yMaxExpected < h.yMax) { yMaxExpected = h.yMax; } } } if (xMin == xMinExpected) { String s = "xMin = " + xMin; v.Pass(T.head_MinMaxValues, P.head_P_xMin_glyf, m_tag, s); } else { string s = "actual: " + xMin + ", expected: " + xMinExpected; v.Error(T.head_MinMaxValues, E.head_E_xMin_glyf, m_tag, s); bRet = false; } if (yMin == yMinExpected) { String s = "yMin = " + yMin; v.Pass(T.head_MinMaxValues, P.head_P_yMin_glyf, m_tag, s); } else { string s = "actual: " + yMin + ", expected: " + yMinExpected; v.Error(T.head_MinMaxValues, E.head_E_yMin_glyf, m_tag, s); bRet = false; } if (xMax == xMaxExpected) { String s = "xMax = " + xMax; v.Pass(T.head_MinMaxValues, P.head_P_xMax_glyf, m_tag, s); } else { string s = "actual: " + xMax + ", expected: " + xMaxExpected; v.Error(T.head_MinMaxValues, E.head_E_xMax_glyf, m_tag, s); bRet = false; } if (yMax == yMaxExpected) { String s = "yMax = " + yMax; v.Pass(T.head_MinMaxValues, P.head_P_yMax_glyf, m_tag, s); } else { string s = "actual: " + yMax + ", expected: " + yMaxExpected; v.Error(T.head_MinMaxValues, E.head_E_yMax_glyf, m_tag, s); bRet = false; } } else { v.Error(T.head_MinMaxValues, E._TEST_E_TableMissing, m_tag, "maxp"); } } else { v.Error(T.head_MinMaxValues, E._TEST_E_TableMissing, m_tag, "glyf"); } } else { v.Info(T.head_MinMaxValues, I._TEST_I_NotForCFF, m_tag, "test = head_MinMaxValues"); } } if (v.PerformTest(T.head_MacStyleBits)) { bool bMacBold = ((macStyle & 0x0001) != 0); bool bMacItal = ((macStyle & 0x0002) != 0); // subfamily (style) string Table_name nameTable = (Table_name)fontOwner.GetTable("name"); string sStyle = null; string sStyleLower = null; if (nameTable != null) { sStyle = nameTable.GetStyleString(); if (sStyle != null) { sStyleLower = sStyle.ToLower(); } } if (sStyleLower != null) { if (bMacBold && sStyleLower.IndexOf("bold") == -1) { v.Error(T.head_MacStyleBits, E.head_E_macStyleBold_subfamily, m_tag, "macStyle bold bit is set, but subfamily is " + sStyle); bRet = false; } else if (!bMacBold && sStyleLower.IndexOf("bold") != -1) { v.Error(T.head_MacStyleBits, E.head_E_macStyleBold_subfamily, m_tag, "macStyle bold bit is clear, but subfamily is " + sStyle); bRet = false; } else { v.Pass(T.head_MacStyleBits, P.head_P_macStyleBold_subfamily, m_tag); } if (bMacItal && sStyleLower.IndexOf("italic") == -1 && sStyleLower.IndexOf("oblique") == -1) { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal_subfamily, m_tag, "macStyle italic bit is set, but subfamily is " + sStyle); bRet = false; } else if (!bMacItal && (sStyleLower.IndexOf("italic") != -1 || sStyleLower.IndexOf("oblique") != -1)) { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal_subfamily, m_tag, "macStyle italic bit is clear, but subfamily is " + sStyle); bRet = false; } else { v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_subfamily, m_tag); } } Table_OS2 OS2Table = (Table_OS2)fontOwner.GetTable("OS/2"); if (OS2Table != null) { // fsSelection bool bOS2Bold = ((OS2Table.fsSelection & 0x0020) != 0); bool bOS2Ital = ((OS2Table.fsSelection & 0x0001) != 0); if (bMacBold == bOS2Bold) { v.Pass(T.head_MacStyleBits, P.head_P_macStyleBold_OS2, m_tag); } else if (bMacBold) { v.Error(T.head_MacStyleBits, E.head_E_macStyleBold1_OS2, m_tag); bRet = false; } else { v.Error(T.head_MacStyleBits, E.head_E_macStyleBold0_OS2, m_tag); bRet = false; } if (bMacItal == bOS2Ital) { v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_OS2, m_tag); } else if (bMacItal) { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal1_OS2, m_tag); bRet = false; } else { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal0_OS2, m_tag); bRet = false; } } Table_post postTable = (Table_post)fontOwner.GetTable("post"); if (postTable != null) { bool bPostItal = (postTable.italicAngle.GetUint() != 0); if (bMacItal == bPostItal) { v.Pass(T.head_MacStyleBits, P.head_P_macStyleItal_post, m_tag); } else if (bMacItal) { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal1_post, m_tag); bRet = false; } else { v.Error(T.head_MacStyleBits, E.head_E_macStyleItal0_post, m_tag); bRet = false; } } } if (v.PerformTest(T.head_LowestRecSize)) { if (lowestRecPPEM == 0) { v.Error(T.head_LowestRecSize, E.head_E_lowestRecPPEM_zero, m_tag); bRet = false; } else if (lowestRecPPEM >= 1 && lowestRecPPEM <= 6) { v.Warning(T.head_LowestRecSize, W.head_W_lowestRecPPEM_small, m_tag, "lowestRecPPEM = " + lowestRecPPEM.ToString()); } else if (lowestRecPPEM >= 36) { v.Warning(T.head_LowestRecSize, W.head_W_lowestRecPPEM_large, m_tag, "lowestRecPPEM = " + lowestRecPPEM.ToString()); } else { v.Pass(T.head_LowestRecSize, P.head_P_lowestRecPPEM, m_tag); } } if (v.PerformTest(T.head_FontDirectionHint)) { if (fontDirectionHint >= -2 && fontDirectionHint <= 2) { v.Pass(T.head_FontDirectionHint, P.head_P_fontDirectionHint, m_tag, fontDirectionHint.ToString()); } else { v.Error(T.head_FontDirectionHint, E.head_E_fontDirectionHint, m_tag, fontDirectionHint.ToString()); bRet = false; } } if (v.PerformTest(T.head_IndexToLocFormat)) { if (fontOwner.ContainsPostScriptOutlines()) { v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_ignore, m_tag, "indexToLocFormat = " + indexToLocFormat); } else { if (indexToLocFormat == 0 || indexToLocFormat == 1) { v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_range, m_tag, indexToLocFormat.ToString()); } else { v.Error(T.head_IndexToLocFormat, E.head_E_indexToLocFormat_range, m_tag, indexToLocFormat.ToString()); bRet = false; } if (indexToLocFormat == 0 || indexToLocFormat == 1) { Table_loca locaTable = (Table_loca)fontOwner.GetTable("loca"); if (locaTable != null) { Table_maxp maxpTable = (Table_maxp)fontOwner.GetTable("maxp"); if (maxpTable != null) { uint locaTableElementSize = 0; if (indexToLocFormat == 0) { locaTableElementSize = 2; } else if (indexToLocFormat == 1) { locaTableElementSize = 4; } uint CalcLocaLength = (uint)(maxpTable.NumGlyphs + 1) * locaTableElementSize; if (CalcLocaLength == locaTable.GetLength()) { v.Pass(T.head_IndexToLocFormat, P.head_P_indexToLocFormat_match, m_tag, indexToLocFormat.ToString()); } else { v.Error(T.head_IndexToLocFormat, E.head_E_indexToLocFormat_match, m_tag, indexToLocFormat.ToString()); bRet = false; } } else { v.Error(T.head_IndexToLocFormat, E._TEST_E_TableMissing, m_tag, "maxp"); } } else { v.Error(T.head_IndexToLocFormat, E._TEST_E_TableMissing, m_tag, "loca"); } } } } if (v.PerformTest(T.head_GlyphDataFormat)) { if (glyphDataFormat == 0) { v.Pass(T.head_GlyphDataFormat, P.head_P_glyphDataFormat, m_tag); } else { v.Error(T.head_GlyphDataFormat, E.head_E_glyphDataFormat, m_tag); bRet = false; } } return(bRet); }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { string sDetails = ""; string [] Apple_Tables = { "acnt", "avar", "bdat", "bhed", "bloc", "bsln", "cmap", "cvar", "cvt ", "EBSC", "fdsc", "feat", "fmtx", "fpgm", "gasp", "glyf", "gvar", "hdmx", "head", "hhea", "hmtx", "hsty", "just", "kern", "lcar", "loca", "maxp", "mort", "morx", "name", "opbd", "OS/2", "post", "prep", "prop", "trak", "vhea", "vmtx", "Zapf" }; string [] VOLT_only_Tables = { "TSIV" }; string [] VOLT_VTT_shared_Tables = { "TSIS", "TSIP", "TSID" }; string [] VTT_only_Tables = { "TSI0", "TSI1", "TSI2", "TSI3", "TSI4", "TSI5" ,"TSIJ", "TSIB" }; bool bIdentified = false; for (int i=0; i<Apple_Tables.Length; i++) { if (Apple_Tables[i] == (string)m_tag) { sDetails = "This table type is defined in the Apple TrueType spec."; bIdentified = true; } } if (!bIdentified) { for (int i=0; i<VOLT_only_Tables.Length; i++) { if (VOLT_only_Tables[i] == (string)m_tag) { sDetails = "This table type is used by the VOLT tool."; bIdentified = true; } } } if (!bIdentified) { for (int i=0; i<VOLT_VTT_shared_Tables.Length; i++) { if (VOLT_VTT_shared_Tables[i] == (string)m_tag) { sDetails = "This table type is used by the VOLT tool and the VTT tool."; bIdentified = true; } } } if (!bIdentified) { for (int i=0; i<VTT_only_Tables.Length; i++) { if (VTT_only_Tables[i] == (string)m_tag) { sDetails = "This table type is used by the VTT tool."; bIdentified = true; } } } v.Info(T.T_NULL, I._Table_I_Non_OT_Table, m_tag, sDetails); // Since there is no way to do any validation on unknown tables // always return true return true; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.DSIG_Formats)) { bool bFormatsOk = true; for (uint i=0; i<usNumSigs; i++) { SigFormatOffset sfo; try { sfo = GetSigFormatOffset(i); if (sfo.ulFormat != 1) { v.Error(T.DSIG_Formats, E.DSIG_E_Formats, m_tag, "block " + i + ", format = " + sfo.ulFormat); bFormatsOk = false; bRet = false; } } catch (IndexOutOfRangeException e) { v.Error(T.DSIG_Formats, E.DSIG_E_Formats, m_tag, "block " + i + ", " + e); bFormatsOk = false; bRet = false; break; // No point continuing } } if (bFormatsOk) { v.Pass(T.DSIG_Formats, P.DSIG_P_Formats, m_tag); } } if (v.PerformTest(T.DSIG_Reserved)) { bool bReservedOk = true; for (uint i=0; i<usNumSigs; i++) { SignatureBlock sb; try { sb = GetSignatureBlock(i); if (sb.usReserved1 != 0 || sb.usReserved2 != 0) { v.Error(T.DSIG_Reserved, E.DSIG_E_Reserved, m_tag, "block " + i); bReservedOk = false; bRet = false; } } catch (IndexOutOfRangeException) { v.Error(T.DSIG_Reserved, E.DSIG_E_Reserved, m_tag, "block " + i); bReservedOk = false; bRet = false; break; // No point continuing } } if (bReservedOk) { v.Pass(T.DSIG_Reserved, P.DSIG_P_Reserved, m_tag); } } if (v.PerformTest(T.DSIG_VerifySignature)) { OTFile file = fontOwner.GetFile(); System.IO.FileStream fs = file.GetFileStream(); String sFilename = fs.Name; try { WinVerifyTrustWrapper wvt = new WinVerifyTrustWrapper(); if (wvt.WinVerifyTrustFile(sFilename)) { if (wvt.usNumSigs > 0) { if (wvt.Warn_TTCv1 || wvt.Warn_DSIG_in_memFonts) v.Warning(T.DSIG_VerifySignature, W.DSIG_W_VerifySignature_Generic, m_tag, ( wvt.Warn_TTCv1 ? "TTC with v1 header;":"") + (wvt.Warn_DSIG_in_memFonts ? "DSIG tables detected in member fonts;":"") ); v.Pass(T.DSIG_VerifySignature, P.DSIG_P_VerifySignature, m_tag, wvt.Signer); } else v.Pass(T.DSIG_VerifySignature, P.DSIG_P_VerifySignature, m_tag); } else { v.Error(T.DSIG_VerifySignature, E.DSIG_E_VerifySignature, m_tag); bRet = false; } } catch (Exception e) { v.Error(T.DSIG_VerifySignature, E.DSIG_E_VerifySignature, m_tag, e.Message); bRet = false; } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.VDMX_Version)) { if (version == 0 || version == 1) { v.Pass(T.VDMX_Version, P.VDMX_P_Version, m_tag, version.ToString()); } else { v.Error(T.VDMX_Version, E.VDMX_E_Version, m_tag, version.ToString()); bRet = false; } } if (v.PerformTest(T.VDMX_Offsets)) { bool bOffsetsOk = true; ushort minPossibleOffset = (ushort)((ushort)FieldOffsets.ratRange + numRatios * 4 + numRatios*2); ushort maxPossibleOffset = (ushort)GetLength(); for (uint i=0; i<numRatios; i++) { ushort offset = GetVdmxGroupOffset(i); if (offset < minPossibleOffset || offset > maxPossibleOffset) { v.Error(T.VDMX_Offsets, E.VDMX_E_InvalidOffset, m_tag, "#" + i + " offset = " + offset); bOffsetsOk = false; bRet = false; } } if (bOffsetsOk) { v.Pass(T.VDMX_Offsets, P.VDMX_P_Offsets, m_tag); } } if (v.PerformTest(T.VDMX_GroupsInTable)) { bool bGroupsOk = true; for (uint i=0; i<numRatios; i++) { Vdmx vdmx = GetVdmxGroup(i); uint EndOffset = (uint)GetVdmxGroupOffset(i) + 4 + (uint)vdmx.recs*6; if (EndOffset > GetLength()) { v.Error(T.VDMX_GroupsInTable, E.VDMX_E_GroupsInTable, m_tag, "group# " + i); bGroupsOk = false; bRet = false; } } if (bGroupsOk) { v.Pass(T.VDMX_GroupsInTable, P.VDMX_P_GroupsInTable, m_tag); } } if (v.PerformTest(T.VDMX_CompareToCalcData)) { bool bDataOk = true; bool needtol = false; RasterInterf.DevMetricsData dmd = null; try { Version ver = fontOwner.GetFile().GetRasterizer().FTVersion; if ( ver.CompareTo(new Version(2,6,1)) < 0 ) v.Warning(T.VDMX_CompareToCalcData, W.VDMX_W_Need_Newer_FreeType, m_tag, "Using FreeType Version " + ver + " may not get correct results for VDMX"); dmd = fontOwner.GetCalculatedDevMetrics(); } catch (InvalidOperationException e) { // JJF Figure out what to do. Changed to warning v.Warning(T.VDMX_CompareToCalcData, W._TEST_W_ErrorInAnotherTable, m_tag, e.Message); } catch(Exception e) { v.ApplicationError(T.VDMX_CompareToCalcData, E._Table_E_Exception, m_tag, e.Message); bRet = false; } if (dmd != null) { for (uint iRatio=0; iRatio<numRatios; iRatio++) { Ratios ratio = GetRatioRange(iRatio); Vdmx group = GetVdmxGroup(iRatio); for (uint iEntry=0; iEntry<group.recs; iEntry++) { Vdmx.vTable vTableEntry = group.GetEntry(iEntry); if (vTableEntry.yPelHeight <= 255) { if (vTableEntry.yPelHeight == dmd.vdmxData.groups[iRatio].entry[vTableEntry.yPelHeight - group.startsz].yPelHeight) { if (vTableEntry.yMin != dmd.vdmxData.groups[iRatio].entry[iEntry].yMin || vTableEntry.yMax != dmd.vdmxData.groups[iRatio].entry[iEntry].yMax){ int dif = dmd.vdmxData.groups[iRatio].entry[iEntry].yMax - dmd.vdmxData.groups[iRatio].entry[iEntry].yMin; if (!TestTolerance(dmd.vdmxData.groups[iRatio].entry[iEntry].yMin, vTableEntry.yMin, dif) || !TestTolerance(dmd.vdmxData.groups[iRatio].entry[iEntry].yMax, vTableEntry.yMax, dif)) { String sDetails = "group[" + iRatio + "], entry[" + iEntry + "], yPelHeight = " + vTableEntry.yPelHeight + ", yMin,yMax = " + vTableEntry.yMin + "," + vTableEntry.yMax + ", calculated yMin,yMax = " + dmd.vdmxData.groups[iRatio].entry[iEntry].yMin + "," + dmd.vdmxData.groups[iRatio].entry[iEntry].yMax; v.Error(T.VDMX_CompareToCalcData, E.VDMX_E_CalcData, m_tag, sDetails); bDataOk = false; } else { needtol = true; } } /* else { String s = "group[" + iRatio + "], yPelHeight = " + vTableEntry.yPelHeight + ", entry OK"; v.DebugMsg(s, m_tag); } */ } else { Debug.Assert(false); } } else { String sDetails = "group[" + iRatio + "], entry[" + iEntry + "], yPelHeight = " + vTableEntry.yPelHeight; v.Error(T.VDMX_CompareToCalcData, E.VDMX_E_yPelHeight_illegal, m_tag, sDetails); bDataOk = false; } } } if (bDataOk) { if (needtol) { String sDetails = "The differences were smaller than the tolerance, so they may well be valid if the VDMX was hand-tuned"; v.Warning(T.VDMX_CompareToCalcData, W.VDMX_W_CalcData, m_tag, sDetails); } else { v.Pass(T.VDMX_CompareToCalcData, P.VDMX_P_CalcData, m_tag); } } else { //v.Error(T.VDMX_CompareToCalcData, E.VDMX_E_CalcData, m_tag); bRet = false; } } else { // Rasterization could not occur for various reasons. string s = "Unable to get calculated device metrics."; v.Error(T.VDMX_CompareToCalcData, E.VDMX_E_CalcData, m_tag, s); bDataOk = false; bRet = false; } } return bRet; }
/************************ * public methods */ public bool Validate(Validator v, OTFontVal fontOwner) { bool bRet = true; if (v.PerformTest(T.OS_2_Version)) { if (version == 0 || version == 1 || version == 2) { v.Warning(T.OS_2_Version, W.OS_2_W_Version_old, m_tag, version.ToString()); } else if (version == 3) { v.Pass(T.OS_2_Version, P.OS_2_P_Version, m_tag, version.ToString()); } else { v.Error(T.OS_2_Version, E.OS_2_E_Version, m_tag, version.ToString()); bRet = false; } } if (v.PerformTest(T.OS_2_TableLength)) { uint len = GetLength(); if ((version == 0 && len == 78) || (version == 1 && len == 86) || (version == 2 && len == 96) || (version == 3 && len == 96)) { v.Pass(T.OS_2_TableLength, P.OS_2_P_TableLength, m_tag); } else { v.Error(T.OS_2_TableLength, E.OS_2_E_TableLength, m_tag); bRet = false; } } if (!bRet) { v.Warning(T.T_NULL, W._TEST_W_OtherErrorsInTable, m_tag, "OS/2 table appears to be corrupt. No further tests will be performed."); return bRet; } if (v.PerformTest(T.OS_2_xAvgCharWidth)) { if (fontOwner.GetTable("maxp") == null) { v.Warning(T.OS_2_xAvgCharWidth, W._TEST_W_ErrorInAnotherTable, m_tag, "maxp table inaccessible, can't check Avg Char Width"); } else { if (fontOwner.ContainsTrueTypeOutlines()) { Table_hmtx hmtxTable = (Table_hmtx)fontOwner.GetTable("hmtx"); val_loca locaTable = (val_loca)fontOwner.GetTable("loca"); val_maxp maxpTable = (val_maxp)fontOwner.GetTable("maxp"); if (hmtxTable == null) { v.Error(T.OS_2_xAvgCharWidth, E._TEST_E_TableMissing, m_tag, "hmtx"); bRet = false; } else if (locaTable == null) { v.Error(T.OS_2_xAvgCharWidth, E._TEST_E_TableMissing, m_tag, "loca"); bRet = false; } else if (maxpTable == null) { v.Error(T.OS_2_xAvgCharWidth, E._TEST_E_TableMissing, m_tag, "maxp"); bRet = false; } else { if ( version == 3 || fontOwner.ContainsMsSymbolEncodedCmap()) { int nTotalWidth = 0; int nTotalGlyphs = 0; for (uint iGlyph=0; iGlyph<fontOwner.GetMaxpNumGlyphs(); iGlyph++) { Table_hmtx.longHorMetric hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner); if (hm != null) { nTotalWidth += hm.advanceWidth; // only average non-zero width glyphs if (hm.advanceWidth > 0) { nTotalGlyphs ++; } } } short CalcAvgWidth = 0; if (nTotalGlyphs > 0) CalcAvgWidth = (short)(nTotalWidth / nTotalGlyphs); if (xAvgCharWidth == CalcAvgWidth) { v.Pass(T.OS_2_xAvgCharWidth, P.OS_2_P_xAvgCharWidth, m_tag); } else { string s = "actual = " + xAvgCharWidth + ", calc = " + CalcAvgWidth; v.Error(T.OS_2_xAvgCharWidth, E.OS_2_E_xAvgCharWidth, m_tag, s); bRet = false; } } else { // do weighed average ushort [] weightLC = { 64, 14, 27, 35, 100, 20, 14, 42, 63, 3, 6, 35, 20, 56, 56, 17, 4, 49, 56, 71, 31, 10, 18, 3, 18, 2 }; ushort weightSpace = 166; try { uint iSpaceGlyph = fontOwner.FastMapUnicodeToGlyphID(' '); if (iSpaceGlyph >= fontOwner.GetMaxpNumGlyphs()) { throw new ApplicationException("error in cmap table"); } Table_hmtx.longHorMetric hmSpace = hmtxTable.GetOrMakeHMetric(iSpaceGlyph, fontOwner); if (hmSpace != null) { int nTotalWeight = hmSpace.advanceWidth * weightSpace; int nLowerCase = 0; for (char c = 'a'; c <= 'z'; c++) { uint iGlyph = fontOwner.FastMapUnicodeToGlyphID(c); if (iGlyph > 0 && iGlyph < fontOwner.GetMaxpNumGlyphs()) { nLowerCase ++; Table_hmtx.longHorMetric hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner); nTotalWeight += hm.advanceWidth * weightLC[c-'a']; } } short CalcAvgWidth = 0; if (nLowerCase == 26) { CalcAvgWidth = (short)(nTotalWeight / 1000); } else { int nTotalWidth = 0; int nTotalGlyphs = 0; for (uint iGlyph=0; iGlyph<fontOwner.GetMaxpNumGlyphs(); iGlyph++) { Table_hmtx.longHorMetric hm = hmtxTable.GetOrMakeHMetric(iGlyph, fontOwner); nTotalWidth += hm.advanceWidth; nTotalGlyphs ++; } CalcAvgWidth = (short)(nTotalWidth / nTotalGlyphs); } if (xAvgCharWidth == CalcAvgWidth) { v.Pass(T.OS_2_xAvgCharWidth, P.OS_2_P_xAvgCharWidth, m_tag); } else { string s = "actual = " + xAvgCharWidth + ", calc = " + CalcAvgWidth; v.Error(T.OS_2_xAvgCharWidth, E.OS_2_E_xAvgCharWidth, m_tag, s); bRet = false; } } else { v.Warning(T.OS_2_xAvgCharWidth, W.OS_2_W_hmtx_invalid, m_tag, "unable to parse hmtx table"); } } catch (ApplicationException e) { v.Warning(T.OS_2_xAvgCharWidth, W._TEST_W_ErrorInAnotherTable, m_tag, "xAvgCharWidth cannot be validated due to " + e.Message); } } } } else { // not a TT outline font - should embedded bitmap only font be handled here? v.Info(T.OS_2_xAvgCharWidth, I._TEST_I_NotForCFF, m_tag, "test = OS/2_xAvgCharWidth"); } } } if (v.PerformTest(T.OS_2_WeightClass)) { if (usWeightClass >= 100 && usWeightClass <= 900 && usWeightClass% 100 == 0) { bool bWeightClassOk = true; // compare to the PANOSE weight value if (panose_byte1 == 2 || panose_byte1 == 3 || panose_byte1 == 4) // latin text, hand writing, or decorative { if (panose_byte3 > 1) { // convert PANOSE weight value from a range of [2..11] to a range of [100..900] (reasonably close anyway, given integer math) int nConvertedPANOSE = (panose_byte3-2)*89+100; int nDifference = Math.Abs(usWeightClass - nConvertedPANOSE); if (nDifference < 200) { v.Pass(T.OS_2_WeightClass, P.OS_2_P_WeightClass_PANOSE, m_tag); } else { v.Warning(T.OS_2_WeightClass, W.OS_2_W_WeightClass_PANOSE, m_tag, "usWeightClass = " + usWeightClass + ", PANOSE weight = " + panose_byte3); bWeightClassOk = false; } } } if (bWeightClassOk) { v.Pass(T.OS_2_WeightClass, P.OS_2_P_WeightClass, m_tag, usWeightClass.ToString()); } } else { v.Error(T.OS_2_WeightClass, E.OS_2_E_WeightClass, m_tag, usWeightClass.ToString()); bRet = false; } } if (v.PerformTest(T.OS_2_WidthClass)) { if (usWidthClass >=1 && usWidthClass <= 9) { v.Pass(T.OS_2_WidthClass, P.OS_2_P_WidthClass, m_tag, usWidthClass.ToString()); } else { v.Error(T.OS_2_WidthClass, E.OS_2_E_WidthClass, m_tag, usWidthClass.ToString()); bRet = false; } } if (v.PerformTest(T.OS_2_fsType)) { bool bPass = true; if ((fsType & 0xfcf1) != 0) { v.Error(T.OS_2_fsType, E.OS_2_E_fsTypeReserved, m_tag, "0x"+fsType.ToString("x4")); bRet = false; bPass = false; } else { int nExclusiveBits = 0; if ((fsType & 0x0002) !=0) //Restricted License Embedding { nExclusiveBits++; } if ((fsType & 0x0004) != 0) // Preview and Print embedding { nExclusiveBits++; } if ((fsType & 0x0008) != 0) // Editable embedding { nExclusiveBits++; } if (nExclusiveBits > 1) { string sDetails = "0x"+fsType.ToString("x4"); if ((fsType & 0x0002) !=0) { sDetails += ", Restricted License Embedding"; } if ((fsType & 0x0004) != 0) { sDetails += ", Preview and Print embedding"; } if ((fsType & 0x0008) != 0) { sDetails += ", Editable embedding"; } v.Error(T.OS_2_fsType, E.OS_2_E_fsTypeExclusiveBits, m_tag, sDetails); bRet = false; bPass = false; } } if (bPass) { string sDetails = "0x"+fsType.ToString("x4"); if (fsType == 0) { sDetails += ", Installable Embedding"; } if ((fsType & 0x0002) !=0) { sDetails += ", Restricted License Embedding"; } if ((fsType & 0x0004) != 0) { sDetails += ", Preview and Print embedding"; } if ((fsType & 0x0008) != 0) { sDetails += ", Editable embedding"; } if ((fsType & 0x0100) != 0) { sDetails += ", No subsetting"; } if ((fsType & 0x0200) != 0) { sDetails += ", Bitmap embedding only"; } v.Pass(T.OS_2_fsType, P.OS_2_P_fsType, m_tag, sDetails); } } if (v.PerformTest(T.OS_2_SubscriptSuperscript)) { Table_head headTable = (Table_head)fontOwner.GetTable("head"); if (headTable != null) { ushort unitsPerEm = headTable.unitsPerEm; ushort SmallestScript = (ushort)(unitsPerEm / 10); bool bNoWarnOrErr = true; if (ySubscriptXSize < SmallestScript || ySubscriptXSize > unitsPerEm ) { v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySubscriptXSize_unlikely, m_tag, ySubscriptXSize.ToString()); bNoWarnOrErr = false; } if (ySubscriptYSize < SmallestScript || ySubscriptYSize > unitsPerEm ) { v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySubscriptYSize_unlikely, m_tag, ySubscriptYSize.ToString()); bNoWarnOrErr = false; } if (ySubscriptYOffset < 0 ) { v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySubscriptYOffset_LTZero, m_tag, ySubscriptYOffset.ToString()); bNoWarnOrErr = false; } if (ySuperscriptXSize < SmallestScript || ySuperscriptXSize > unitsPerEm ) { v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySuperscriptXSize_unlikely, m_tag, ySuperscriptXSize.ToString()); bNoWarnOrErr = false; } if (ySuperscriptYSize < SmallestScript || ySuperscriptYSize > unitsPerEm ) { v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySuperscriptYSize_unlikely, m_tag, ySuperscriptYSize.ToString()); bNoWarnOrErr = false; } if (ySuperscriptYOffset < 0 ) { v.Warning(T.OS_2_SubscriptSuperscript, W.OS_2_W_ySuperscriptYOffset_unlikely, m_tag, ySuperscriptYOffset.ToString()); bNoWarnOrErr = false; } if (bNoWarnOrErr) { v.Pass(T.OS_2_SubscriptSuperscript, P.OS_2_P_SuperscriptSubscript, m_tag); } } else { v.Error(T.OS_2_SubscriptSuperscript, E._TEST_E_TableMissing, m_tag, "head"); bRet = false; } } if (v.PerformTest(T.OS_2_Strikeout)) { Table_head headTable = (Table_head)fontOwner.GetTable("head"); if (headTable != null) { ushort unitsPerEm = headTable.unitsPerEm; bool bNoWarnings = true; if (yStrikeoutSize < 0 || yStrikeoutSize > unitsPerEm / 2 ) { v.Warning(T.OS_2_Strikeout, W.OS_2_W_yStrikeoutSize_unlikely, m_tag, yStrikeoutSize.ToString()); bNoWarnings = false; } if (yStrikeoutPosition <= 0 ) { v.Warning(T.OS_2_Strikeout, W.OS_2_W_yStrikeoutPosition_unlikely, m_tag, yStrikeoutPosition.ToString()); bNoWarnings = false; } if (bNoWarnings) { v.Pass(T.OS_2_Strikeout, P.OS_2_P_Strikeout, m_tag); } } else { v.Error(T.OS_2_Strikeout, E._TEST_E_TableMissing, m_tag, "head"); bRet = false; } } if (v.PerformTest(T.OS_2_FamilyClass)) { bool bIDsOk = true; byte ClassID = (byte)(sFamilyClass >> 8); byte SubclassID = (byte)(sFamilyClass); if (ClassID == 6 || ClassID == 11 || ClassID == 13 || ClassID == 14 ) { v.Error(T.OS_2_FamilyClass, E.OS_2_E_sFamilyClass_classID_reserved, m_tag, ClassID.ToString()); bIDsOk = false; bRet = false; } if (ClassID > 14 ) { v.Error(T.OS_2_FamilyClass, E.OS_2_E_sFamilyClass_ClassID_undefined, m_tag, ClassID.ToString()); bIDsOk = false; bRet = false; } if (SubclassID > 15 ) { v.Error(T.OS_2_FamilyClass, E.OS_2_E_sFamilyClass_subclassID_undefined, m_tag, ClassID.ToString()); bIDsOk = false; bRet = false; } if (bIDsOk) { v.Pass(T.OS_2_FamilyClass, P.OS_2_P_sFamilyClass, m_tag); } } if (v.PerformTest(T.OS_2_Panose)) { bool bPanoseOk = true; if (panose_byte1 < 5) // panose kind valid, but not latin symbol { if (fontOwner.ContainsSymbolsOnly()) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_FamilyTypeNotSymbol, m_tag, "PANOSE byte 1 = " + panose_byte1.ToString()); bPanoseOk = false; bRet = false; } } else if (panose_byte1 == 5) // panose family kind == latin symbol { if (!fontOwner.ContainsSymbolsOnly()) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_FamilyTypeSymbol, m_tag, "PANOSE byte 1 = " + panose_byte1.ToString()); bPanoseOk = false; bRet = false; } } else if ( panose_byte1 > 5 ) // family kind is invalid { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bFamilyType, m_tag, panose_byte1.ToString()); bPanoseOk = false; bRet = false; } if (panose_byte1 == 2) // family kind == latin text { if ( panose_byte2 > 15 ) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bSerifStyle, m_tag, panose_byte2.ToString()); bPanoseOk = false; bRet = false; } } if ( panose_byte3 > 11 ) // byte3 always means weight { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bWeight, m_tag, panose_byte3.ToString()); bPanoseOk = false; bRet = false; } if (panose_byte1 == 5) // panose family kind == latin symbol { if (panose_byte3 != 1) // weight must be 1 for symbols { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_SymbolWeight, m_tag, panose_byte3.ToString()); bPanoseOk = false; bRet = false; } if (panose_byte5 != 1) // aspect ratio & contrast must be 1 for symbols { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_SymbolAspectRatio, m_tag, panose_byte5.ToString()); bPanoseOk = false; bRet = false; } } if (panose_byte1 == 2) // family kind == latin text { // the following tests are only valid when family kind is latin text if ( panose_byte4 > 9 ) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bProportion, m_tag, panose_byte4.ToString()); bPanoseOk = false; bRet = false; } if ( panose_byte5 > 9 ) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bContrast, m_tag, panose_byte5.ToString()); bPanoseOk = false; bRet = false; } if ( panose_byte6 > 10 ) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bStrokeVariation, m_tag, panose_byte6.ToString()); bPanoseOk = false; bRet = false; } if ( panose_byte7 > 11 ) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bArmStyle, m_tag, panose_byte7.ToString()); bPanoseOk = false; bRet = false; } if ( panose_byte8 > 15 ) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bLetterform, m_tag, panose_byte8.ToString()); bPanoseOk = false; bRet = false; } if ( panose_byte9 > 13 ) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bMidline, m_tag, panose_byte9.ToString()); bPanoseOk = false; bRet = false; } if ( panose_byte10 > 7 ) { v.Error(T.OS_2_Panose, E.OS_2_E_Panose_bXHeight, m_tag, panose_byte10.ToString()); bPanoseOk = false; bRet = false; } } if (panose_byte1 == 0 && panose_byte2 == 0 && panose_byte3 == 0 && panose_byte4 == 0 && panose_byte5 == 0 && panose_byte6 == 0 && panose_byte7 == 0 && panose_byte8 == 0 && panose_byte9 == 0 && panose_byte10 == 0 ) { v.Warning(T.OS_2_Panose, W.OS_2_W_Panose_undefined, m_tag); bPanoseOk = false; } if (bPanoseOk) { v.Pass(T.OS_2_Panose, P.OS_2_P_Panose, m_tag); } } if (v.PerformTest(T.OS_2_UnicodeRanges)) { bRet &= CheckUnicodeRanges(v, fontOwner); } if (v.PerformTest(T.OS_2_fsSelection)) { bool bSelOk = true; Table_name nameTable = (Table_name)fontOwner.GetTable("name"); string sStyle = null; string sStyleLower = null; if (nameTable != null) { sStyle = nameTable.GetStyleString(); if (sStyle != null) { sStyleLower = sStyle.ToLower(); } } // reserved bits if ( (fsSelection & 0xFF80 ) != 0 ) { // we need to look for Win 3.1 font pages // Fonts with these const ushort HEBREW_FONT_PAGE = 0xB100; const ushort SIMP_ARABIC_FONT_PAGE = 0xB200; const ushort TRAD_ARABIC_FONT_PAGE = 0xB300; const ushort OEM_ARABIC_FONT_PAGE = 0xB400; const ushort SIMP_FARSI_FONT_PAGE = 0xBA00; const ushort TRAD_FARSI_FONT_PAGE = 0xBB00; const ushort THAI_FONT_PAGE = 0xDE00; String sDetails = "Bit(s) "; bool bFoundFirstBadBit = false; if (version == 0) { switch (fsSelection & 0xFF00) { case HEBREW_FONT_PAGE: sDetails = "Hebrew Windows 3.1 font page"; break; case SIMP_ARABIC_FONT_PAGE: sDetails = "Simplified Arabic Windows 3.1 font page"; break; case TRAD_ARABIC_FONT_PAGE: sDetails = "Traditional Arabic Windows 3.1 font page"; break; case OEM_ARABIC_FONT_PAGE: sDetails = "OEM Arabic Windows 3.1 font page"; break; case SIMP_FARSI_FONT_PAGE: sDetails = "Simplified Farsi Windows 3.1 font page"; break; case TRAD_FARSI_FONT_PAGE: sDetails = "Traditional Farsi Windows 3.1 font page"; break; case THAI_FONT_PAGE: sDetails = "Thai Windows 3.1 font page"; break; default: for (int i=0; i<16; i++) { int nBitValue = 1<<i; if ((nBitValue & 0xFF80) != 0) { if ((fsSelection & nBitValue) != 0) { if (bFoundFirstBadBit) { sDetails += ", " + i; } else { sDetails += i.ToString(); bFoundFirstBadBit = true; } } } } break; } } else { for (int i=0; i<16; i++) { int nBitValue = 1<<i; if ((nBitValue & 0xFF80) != 0) { if ((fsSelection & nBitValue) != 0) { if (bFoundFirstBadBit) { sDetails += ", " + i; } else { sDetails += i.ToString(); bFoundFirstBadBit = true; } } } } } v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_undefbits, m_tag, sDetails); bSelOk = false; bRet = false; } // compare to head.macStyle italic and bold bits Table_head headTable = (Table_head)fontOwner.GetTable("head"); if (headTable != null) { bool bItalic = ((fsSelection & 0x01) != 0 ); bool bBold = ((fsSelection & 0x20) != 0 ); bool bMacBold = ((headTable.macStyle & 0x0001) != 0); bool bMacItal = ((headTable.macStyle & 0x0002) != 0); if (bItalic != bMacItal) { string sDetails = null; if (bItalic) sDetails = "fsSelection italic bit is set, but macstyle italic bit is clear"; else sDetails = "fsSelection italic bit is clear, but macstyle italic bit is set"; v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_macStyle_italic, m_tag, sDetails); bSelOk = false; bRet = false; } if (bBold != bMacBold) { string sDetails = null; if (bBold) sDetails = "fsSelection bold bit is set, but macstyle bold bit is clear"; else sDetails = "fsSelection bold bit is clear, but macstyle bold bit is set"; v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_macStyle_bold, m_tag, sDetails); bSelOk = false; bRet = false; } } if ((fsSelection & 0x01) != 0 ) // italic bit { // compare to name subfamily if (sStyleLower != null) { if (sStyleLower.IndexOf("italic") == -1 && sStyleLower.IndexOf("oblique") == -1) { v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_subfamily, m_tag, "fsSelection italic bit is set, but subfamily is " + sStyle); bSelOk = false; bRet = false; } } } if ((fsSelection & 0x20) != 0 ) // bold bit { // compare to name subfamily if (sStyleLower != null) { if (sStyleLower.IndexOf("bold") == -1) { v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_subfamily, m_tag, "fsSelection bold bit is set, but subfamily is " + sStyle); bSelOk = false; bRet = false; } } if (usWeightClass <= 500) { v.Warning(T.OS_2_fsSelection, W.OS_2_W_fsSelection_weight, m_tag, "usWeightClass = " + usWeightClass); bSelOk = false; } } if ((fsSelection & 0x40) != 0 ) // regular bit { if ((fsSelection & 0x20) != 0 ) { v.Error(T.OS_2_fsSelection, E.OS_2_E_reg_bold, m_tag); bSelOk = false; bRet = false; } if ((fsSelection & 0x01) != 0) { v.Error(T.OS_2_fsSelection, E.OS_2_E_reg_ital, m_tag); bSelOk = false; bRet = false; } if (sStyleLower != null) { // compare to name subfamily if (sStyleLower.CompareTo("regular") != 0) { v.Error(T.OS_2_fsSelection, E.OS_2_E_fsSelection_subfamily, m_tag, "fsSelection regular bit is set, but subfamily is " + sStyle); bSelOk = false; bRet = false; } } } if (bSelOk) { v.Pass(T.OS_2_fsSelection, P.OS_2_P_fsSelection, m_tag); } } if (v.PerformTest(T.OS_2_CharIndexes)) { Table_cmap cmapTable = (Table_cmap)fontOwner.GetTable("cmap"); if (cmapTable != null) { ushort charFirst = 0xffff; ushort charLast = 0; Table_cmap.EncodingTableEntry eteUni = cmapTable.GetEncodingTableEntry(3,1); if (eteUni == null) { // presumably a symbol font eteUni = cmapTable.GetEncodingTableEntry(3,0); } if (eteUni != null) { Table_cmap.Subtable st = cmapTable.GetSubtable(eteUni); if (st != null) { bool bCmapOk = true; byte[] charbuf = new byte[2]; // find the first char for (ushort c=0; c<0xffff; c++) { charbuf[0] = (byte)c; charbuf[1] = (byte)(c>>8); uint glyphID; try { glyphID = st.MapCharToGlyph(charbuf, 0); } catch { bCmapOk = false; break; } if (glyphID != 0) { charFirst = c; break; } } // find the last char (start at fffd: fffe and ffff aren't legal characters) if (bCmapOk) { for (ushort c=0xfffd; c>0; c--) { charbuf[0] = (byte)c; charbuf[1] = (byte)(c>>8); uint glyphID; try { glyphID = st.MapCharToGlyph(charbuf, 0); } catch { bCmapOk = false; break; } if (glyphID != 0) { charLast = c; break; } } } if (!bCmapOk) { v.Warning(T.OS_2_CharIndexes, W._TEST_W_ErrorInAnotherTable, m_tag, "usFirstCharIndex and usLastCharIndex cannot be validated due to errors in the cmap table"); } else if (usFirstCharIndex == charFirst && usLastCharIndex == charLast) { v.Pass(T.OS_2_CharIndexes, P.OS_2_P_CharIndexes, m_tag, "first = 0x" + usFirstCharIndex.ToString("x4") + ", last = 0x" + usLastCharIndex.ToString("x4")); } else { if (usFirstCharIndex != charFirst) { String sDetails = "actual = 0x" + usFirstCharIndex.ToString("x4") + ", calculated = 0x" + charFirst.ToString("x4"); v.Error(T.OS_2_CharIndexes, E.OS_2_E_usFirstCharIndex, m_tag, sDetails); bRet = false; } if (usLastCharIndex != charLast) { String sDetails = "actual = 0x" + usLastCharIndex.ToString("x4") + ", calculated = 0x" + charLast.ToString("x4"); v.Error(T.OS_2_CharIndexes, E.OS_2_E_usLastCharIndex, m_tag, sDetails); bRet = false; } } } else { v.Warning(T.OS_2_CharIndexes, W._TEST_W_ErrorInAnotherTable, m_tag, "usFirstCharIndex and usLastCharIndex cannot be validated due to errors in the cmap table"); } } } else { v.Error(T.OS_2_CharIndexes, E._TEST_E_TableMissing, m_tag, "cmap"); bRet = false; } } if (v.PerformTest(T.OS_2_TypoMetrics)) { bool bOk = true; if (sTypoAscender <= 0) { v.Error(T.OS_2_TypoMetrics, E.OS_2_E_sTypoAscender_notpositive, m_tag, sTypoAscender.ToString()); bOk = false; bRet = false; } if (sTypoDescender > 0) { v.Error(T.OS_2_TypoMetrics, E.OS_2_E_sTypoDescender_positive, m_tag, sTypoDescender.ToString()); bOk = false; bRet = false; } Table_head headTable = (Table_head)fontOwner.GetTable("head"); if (headTable != null) { if (sTypoAscender - sTypoDescender > headTable.unitsPerEm) { string sDetails = "sTypoAscender = " + sTypoAscender + ", sTypoDescender = " + sTypoDescender; v.Warning(T.OS_2_TypoMetrics, W.OS_2_W_sTypoAscenderDescender_difference, m_tag, sDetails); bOk = false; } } else { v.Error(T.OS_2_TypoMetrics, E._TEST_E_TableMissing, m_tag, "head"); bRet = false; } if (bOk) { string sDetails = "sTypoAscender = " + sTypoAscender + ", sTypoDescender = " + sTypoDescender; v.Pass(T.OS_2_TypoMetrics, P.OS_2_P_sTypoAscenderDescender, m_tag, sDetails); } } if (v.PerformTest(T.OS_2_CodePageRanges)) { if (version >= 1) { bRet &= CheckCodePageRanges(v, fontOwner); } } if (v.PerformTest(T.OS_2_sxHeight)) { if (version >= 2) { if (sxHeight == 0) { if (fontOwner.FastMapUnicodeToGlyphID((char)0x0078) != 0) { v.Error(T.OS_2_sxHeight, E.OS_2_E_sxHeight, m_tag); bRet = false; } else { v.Pass(T.OS_2_sxHeight, P.OS_2_P_sxHeight_zero, m_tag, sxHeight.ToString()); } } else { v.Pass(T.OS_2_sxHeight, P.OS_2_P_sxHeight_nonzero, m_tag, sxHeight.ToString()); } } } if (v.PerformTest(T.OS_2_sCapHeight)) { if (version >= 2) { if (sCapHeight == 0) { if (fontOwner.FastMapUnicodeToGlyphID((char)0x0048) != 0) { v.Error(T.OS_2_sCapHeight, E.OS_2_E_sCapHeight, m_tag); bRet = false; } else { v.Pass(T.OS_2_sCapHeight, P.OS_2_P_sCapHeight_zero, m_tag, sCapHeight.ToString()); } } else { v.Pass(T.OS_2_sCapHeight, P.OS_2_P_sCapHeight_nonzero, m_tag, sCapHeight.ToString()); } } } if (v.PerformTest(T.OS_2_usDefaultChar)) { if (version >= 2) { if (usDefaultChar == 0) { v.Pass(T.OS_2_usDefaultChar, P.OS_2_P_usDefaultChar_zero, m_tag); } else if (fontOwner.FastMapUnicodeToGlyphID((char)usDefaultChar) != 0) { v.Pass(T.OS_2_usDefaultChar, P.OS_2_P_usDefaultChar_nonzero, m_tag, "0x" + usDefaultChar.ToString("x4")); } else { v.Error(T.OS_2_usDefaultChar, E.OS_2_E_usDefaultChar_notmapped, m_tag, "0x" + usDefaultChar.ToString("x4")); bRet = false; } } } if (v.PerformTest(T.OS_2_usBreakChar)) { if (version >= 2) { if (fontOwner.FastMapUnicodeToGlyphID((char)usBreakChar) != 0) { v.Pass(T.OS_2_usBreakChar, P.OS_2_P_usBreakChar_mapped, m_tag); } else { v.Error(T.OS_2_usBreakChar, E.OS_2_E_usBreakChar_notmapped, m_tag, "0x" + usBreakChar.ToString("x4")); bRet = false; } } } if (v.PerformTest(T.OS_2_usMaxContext)) { if (version >= 2) { ushort GPOSMaxContext = 0; Table_GPOS GPOSTable = (Table_GPOS)fontOwner.GetTable("GPOS"); if (GPOSTable != null) { GPOSMaxContext = GPOSTable.GetMaxContext(); } ushort GSUBMaxContext = 0; Table_GSUB GSUBTable = (Table_GSUB)fontOwner.GetTable("GSUB"); if (GSUBTable != null) { GSUBMaxContext = GSUBTable.GetMaxContext(); } ushort CalcMaxContext = Math.Max(GPOSMaxContext, GSUBMaxContext); if (usMaxContext == CalcMaxContext) { v.Pass(T.OS_2_usMaxContext, P.OS_2_P_usMaxContext, m_tag, usMaxContext.ToString()); } else { v.Error(T.OS_2_usMaxContext, E.OS_2_E_usMaxContext, m_tag, "calc = " + CalcMaxContext + ", actual = " + usMaxContext); bRet = false; } } } return bRet; }