Example #1
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;
        }
Example #2
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);
        }
        /************************
         * 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;
        }