Inheritance: OTFontFile.OTFont
示例#1
0
        /************************
         * 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);
        }
示例#2
0
        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);
        }
示例#3
0
        /************************
         * 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;
        }
示例#4
0
        /************************
         * 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);
        }
示例#6
0
        /************************
         * 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;
        }
示例#7
0
        /************************
         * 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;
        }
示例#8
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            v.Info(I.fpgm_I_NotValidated, m_tag);
            
            return bRet;
        }
示例#9
0
        /************************
         * public methods
         */


        public bool Validate(Validator v, OTFontVal fontOwner)
        {
            bool bRet = true;

            v.Info(I.fpgm_I_NotValidated, m_tag);

            return(bRet);
        }
示例#10
0
        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);
        }
示例#11
0
        /************************
         * 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;
        }
示例#12
0
        /************************
         * 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);
        }
示例#13
0
        /************************
         * 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;
        }
示例#14
0
        /************************
         * 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);
        }
示例#15
0
        /************************
         * 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);
        }
示例#16
0
        /************************
         * 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;
        }
示例#17
0
        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);
        }
示例#18
0
        /************************
         * 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);
        }
示例#19
0
        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;
        }
示例#20
0
        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;
        }
示例#21
0
        /*****************
        * 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;

        }
示例#22
0
        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;
        }
示例#23
0
        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;
        }
示例#24
0
        /************************
         * 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);
        }
示例#25
0
        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);
        }
示例#26
0
        /************************
         * 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);
        }
示例#27
0
        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);
        }
示例#28
0
        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;
        }
示例#29
0
        /************************
         * 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;
        }
示例#30
0
        /************************
         * 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;
        }
示例#31
0
        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;

        }
示例#32
0
        /************************
         * 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;
        }
示例#33
0
        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);
        }
示例#34
0
        /************************
         * 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;
        }
示例#35
0
        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);
        }
示例#36
0
        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);
        }
示例#37
0
        /************************
         * 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;
        }
示例#38
0
        /************************
         * 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;
        }
示例#39
0
        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);
        }
示例#40
0
        /************************
         * 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);
        }
示例#41
0
        /*****************
         * 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);
        }
示例#42
0
        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;
        }
示例#43
0
        /************************
         * 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;
        }
示例#44
0
        /************************
         * 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);
        }
示例#45
0
        /************************
         * 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);
        }
示例#46
0
        /************************
         * 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);
        }
示例#47
0
        /************************
         * 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;
        }
示例#48
0
        /************************
         * 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;
        }
示例#49
0
        /************************
         * 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;
        }
示例#50
0
        /************************
         * 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;
        }
示例#51
0
        /************************
         * 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);
        }
示例#52
0
        /************************
         * 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);
        }
示例#53
0
        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);
        }
示例#54
0
        /************************
         * 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;
        }
示例#55
0
        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);
        }
示例#56
0
        /************************
         * 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);
        }
示例#57
0
        /************************
         * 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;
        }
示例#58
0
        /************************
         * 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;
        }
示例#59
0
        /************************
         * 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;
        }
示例#60
0
        /************************
         * 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;
        }