XmlCollation.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / XmlUtils / System / Xml / Xsl / Runtime / XmlCollation.cs / 1 / XmlCollation.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System.ComponentModel; 
using System.Diagnostics;
using System.Globalization; 
using System.IO;

namespace System.Xml.Xsl.Runtime {
    using Res = System.Xml.Utils.Res; 

    [EditorBrowsable(EditorBrowsableState.Never)] 
    public sealed class XmlCollation { 
        // lgid support for sort
        private const int deDE = 0x0407; 
        private const int huHU = 0x040E;
        private const int jaJP = 0x0411;
        private const int kaGE = 0x0437;
        private const int koKR = 0x0412; 
        private const int zhTW = 0x0404;
        private const int zhCN = 0x0804; 
        private const int zhHK = 0x0C04; 
        private const int zhSG = 0x1004;
        private const int zhMO = 0x1404; 
        private const int zhTWbopo = 0x030404;
        private const int deDEphon = 0x010407;
        private const int huHUtech = 0x01040e;
        private const int kaGEmode = 0x010437; 

        // Sort ID 
        private const int strksort = 0x02;      // Stroke 
        private const int unicsort = 0x01;      // Unicode
 
        // Options
        private const string ignoreCaseStr      = "IGNORECASE";
        private const string ignoreKanatypeStr  = "IGNOREKANATYPE";
        private const string ignoreNonspaceStr  = "IGNORENONSPACE"; 
        private const string ignoreSymbolsStr   = "IGNORESYMBOLS";
        private const string ignoreWidthStr     = "IGNOREWIDTH"; 
        private const string upperFirstStr      = "UPPERFIRST"; 
        private const string emptyGreatestStr   = "EMPTYGREATEST";
        private const string descendingOrderStr = "DESCENDINGORDER"; 
        private const string sortStr            = "SORT";

        private bool upperFirst;
        private bool emptyGreatest; 
        private bool descendingOrder;
        private CultureInfo cultinfo; 
        private CompareOptions compops; 

 
        //-----------------------------------------------
        // Constructors
        //-----------------------------------------------
 
        /// 
        /// By default, create a collation that uses the current thread's culture, and has no compare options set 
        ///  
        private XmlCollation() : this(null, CompareOptions.None) {
        } 

        /// 
        /// Construct a collation that uses the specified culture and compare options.
        ///  
        private XmlCollation(CultureInfo cultureInfo, CompareOptions compareOptions) {
            this.cultinfo = cultureInfo; 
            this.compops = compareOptions; 
        }
 

        //-----------------------------------------------
        // Create
        //----------------------------------------------- 

        ///  
        /// Singleton collation that sorts according to Unicode code points. 
        /// 
        private static XmlCollation cp = new XmlCollation(CultureInfo.InvariantCulture, CompareOptions.Ordinal); 
        internal static XmlCollation CodePointCollation {
            get { return cp; }
        }
 
        /// 
        /// This function is used in both parser and f&o library, so just strictly map valid literals to XmlCollation. 
        /// Set compare options one by one: 
        ///     0, false: no effect; 1, true: yes
        /// Disregard unrecognized options. 
        /// 
        internal static XmlCollation Create(string collationLiteral) {
            Debug.Assert(collationLiteral != null, "collation literal should not be null");
 
            if (collationLiteral == XmlReservedNs.NsCollCodePoint) {
                return CodePointCollation; 
            } 

            XmlCollation coll = new XmlCollation(); 
            Uri collationUri = new Uri(collationLiteral);

            string authority = collationUri.GetLeftPart(UriPartial.Authority);
            if (authority == XmlReservedNs.NsCollationBase) { 
                // Language
                // at least a '/' will be returned for Uri.LocalPath 
                string lang = collationUri.LocalPath.Substring(1); 
                if (lang.Length == 0) {
                    // Use default culture of current thread (cultinfo = null) 
                } else {
                    // Create culture from RFC 1766 string
                    try {
                        coll.cultinfo = new CultureInfo(lang); 
                    }
                    catch (ArgumentException) { 
                        throw new XslTransformException(Res.Coll_UnsupportedLanguage, lang); 
                    }
                } 
            } else if (collationUri.IsBaseOf(new Uri(XmlReservedNs.NsCollCodePoint))) {
                // language with codepoint collation is not allowed
                coll.compops = CompareOptions.Ordinal;
            } else { 
                // Unrecognized collation
                throw new XslTransformException(Res.Coll_Unsupported, collationLiteral); 
            } 

            // Sort & Compare option 
            // at least a '?' will be returned for Uri.Query if not empty
            string query = collationUri.Query;
            string sort = null;
 
            if (query.Length != 0) {
                foreach (string option in query.Substring(1).Split('&')) { 
                    string[] pair = option.Split('='); 

                    if (pair.Length != 2) 
                        throw new XslTransformException(Res.Coll_BadOptFormat, option);

                    string optionName = pair[0].ToUpper(CultureInfo.InvariantCulture);
                    string optionValue = pair[1].ToUpper(CultureInfo.InvariantCulture); 

                    if (optionName == sortStr) { 
                        sort = optionValue; 
                    }
                    else if (optionValue == "1" || optionValue == "TRUE") { 
                        switch (optionName) {
                        case ignoreCaseStr:        coll.compops |= CompareOptions.IgnoreCase; break;
                        case ignoreKanatypeStr:    coll.compops |= CompareOptions.IgnoreKanaType; break;
                        case ignoreNonspaceStr:    coll.compops |= CompareOptions.IgnoreNonSpace; break; 
                        case ignoreSymbolsStr:     coll.compops |= CompareOptions.IgnoreSymbols; break;
                        case ignoreWidthStr:       coll.compops |= CompareOptions.IgnoreWidth; break; 
                        case upperFirstStr:        coll.upperFirst = true; break; 
                        case emptyGreatestStr:     coll.emptyGreatest = true; break;
                        case descendingOrderStr:   coll.descendingOrder = true; break; 
                        default:
                            throw new XslTransformException(Res.Coll_UnsupportedOpt, pair[0]);
                        }
                    } 
                    else if (optionValue == "0" || optionValue == "FALSE") {
                        switch (optionName) { 
                        case ignoreCaseStr:        coll.compops &= ~CompareOptions.IgnoreCase; break; 
                        case ignoreKanatypeStr:    coll.compops &= ~CompareOptions.IgnoreKanaType; break;
                        case ignoreNonspaceStr:    coll.compops &= ~CompareOptions.IgnoreNonSpace; break; 
                        case ignoreSymbolsStr:     coll.compops &= ~CompareOptions.IgnoreSymbols; break;
                        case ignoreWidthStr:       coll.compops &= ~CompareOptions.IgnoreWidth; break;
                        case upperFirstStr:        coll.upperFirst = false; break;
                        case emptyGreatestStr:     coll.emptyGreatest = false; break; 
                        case descendingOrderStr:   coll.descendingOrder = false; break;
                        default: 
                            throw new XslTransformException(Res.Coll_UnsupportedOpt, pair[0]); 
                        }
                    } 
                    else {
                        throw new XslTransformException(Res.Coll_UnsupportedOptVal, pair[0], pair[1]);
                    }
                } 
            }
 
            // upperfirst option is only meaningful when not ignore case 
            if (coll.upperFirst && (coll.compops & CompareOptions.IgnoreCase) != 0)
                coll.upperFirst = false; 

            // other CompareOptions are only meaningful if Ordinal comparison is not being used
            if ((coll.compops & CompareOptions.Ordinal) != 0) {
                coll.compops = CompareOptions.Ordinal; 
                coll.upperFirst = false;
            } 
 
            // new cultureinfo based on alternate sorting option
            if (sort != null && coll.cultinfo != null) { 
                int lgid = GetLangID(coll.cultinfo.LCID);
                switch (sort) {
                case "bopo":
                    if (lgid == zhTW) { 
                        coll.cultinfo = new CultureInfo(zhTWbopo);
                    } 
                    break; 
                case "strk":
                    if (lgid == zhCN || lgid == zhHK || lgid == zhSG || lgid == zhMO) { 
                        coll.cultinfo = new CultureInfo(MakeLCID(coll.cultinfo.LCID, strksort));
                    }
                    break;
                case "uni": 
                    if (lgid == jaJP || lgid == koKR) {
                        coll.cultinfo = new CultureInfo(MakeLCID(coll.cultinfo.LCID, unicsort)); 
                    } 
                    break;
                case "phn": 
                    if (lgid == deDE) {
                        coll.cultinfo = new CultureInfo(deDEphon);
                    }
                    break; 
                case "tech":
                    if (lgid == huHU) { 
                        coll.cultinfo = new CultureInfo(huHUtech); 
                    }
                    break; 
                case "mod":
                    // ka-GE(Georgian - Georgia) Modern Sort: 0x00010437
                    if (lgid == kaGE) {
                        coll.cultinfo = new CultureInfo(kaGEmode); 
                    }
                    break; 
                case "pron": case "dict": case "trad": 
                    // es-ES(Spanish - Spain) Traditional: 0x0000040A
                    // They are removing 0x040a (Spanish Traditional sort) in NLS+. 
                    // So if you create 0x040a, it's just like 0x0c0a (Spanish International sort).
                    // Thus I don't handle it differently.
                    break;
                default: 
                    throw new XslTransformException(Res.Coll_UnsupportedSortOpt, sort);
                } 
            } 
            return coll;
        } 


        //-----------------------------------------------
        // Convert options to and from an integer 
        //-----------------------------------------------
 
        private const int FlagUpperFirst      = 0x1000; 
        private const int FlagEmptyGreatest   = 0x2000;
        private const int FlagDescendingOrder = 0x4000; 
        private const int CollationFlagsMask  = FlagUpperFirst | FlagEmptyGreatest | FlagDescendingOrder;

        private int GetOptions() {
            int result = (int)this.compops; 
            Debug.Assert((result & CollationFlagsMask) == 0, "CompareOptions and collation flags overlap");
 
            if (upperFirst) 
                result |= FlagUpperFirst;
 
            if (emptyGreatest)
                result |= FlagEmptyGreatest;

            if (descendingOrder) 
                result |= FlagDescendingOrder;
 
            return result; 
        }
 
        private void SetOptions(int options) {
            this.upperFirst       = (options & FlagUpperFirst     ) != 0;
            this.emptyGreatest    = (options & FlagEmptyGreatest  ) != 0;
            this.descendingOrder  = (options & FlagDescendingOrder) != 0; 
            this.compops = (CompareOptions)(options & ~CollationFlagsMask);
        } 
 

        //----------------------------------------------- 
        // Collection Support
        //-----------------------------------------------

        // Redefine Equals and GetHashCode methods, they are needed for UniqueList 
        public override bool Equals(object obj) {
            if (this == obj) { 
                return true; 
            }
 
            XmlCollation that = obj as XmlCollation;
            return that != null &&
                this.GetOptions() == that.GetOptions() &&
                object.Equals(this.cultinfo, that.cultinfo); 
        }
 
        public override int GetHashCode() { 
            int hashCode = this.GetOptions();
            if (this.cultinfo != null) { 
                hashCode ^= this.cultinfo.GetHashCode();
            }
            return hashCode;
        } 

 
        //----------------------------------------------- 
        // Serialization Support
        //----------------------------------------------- 

        // Denotes the current thread locale
        private const int LOCALE_CURRENT = -1;
 
        internal void GetObjectData(BinaryWriter writer) {
            // NOTE: For CultureInfo we serialize only LCID. It seems to suffice for our purposes. 
            Debug.Assert(this.cultinfo == null || this.cultinfo.Equals(new CultureInfo(this.cultinfo.LCID)), 
                "Cannot serialize CultureInfo correctly");
            writer.Write(this.cultinfo != null ? this.cultinfo.LCID : LOCALE_CURRENT); 
            writer.Write(this.GetOptions());
        }

        internal XmlCollation(BinaryReader reader) { 
            int lcid = reader.ReadInt32();
            this.cultinfo = (lcid != LOCALE_CURRENT) ? new CultureInfo(lcid) : null; 
            this.SetOptions(reader.ReadInt32()); 
        }
 

        //-----------------------------------------------
        // Compare Properties
        //----------------------------------------------- 

        internal bool EmptyGreatest { 
            get { return this.emptyGreatest; } 
        }
 
        internal bool DescendingOrder {
            get { return this.descendingOrder; }
        }
 
        internal CultureInfo Culture {
            get { 
                // Use default thread culture if this.cultinfo = null 
                if (this.cultinfo == null)
                    return CultureInfo.CurrentCulture; 

                return this.cultinfo;
            }
        } 

 
        //----------------------------------------------- 
        //
        //----------------------------------------------- 

        /// 
        /// Create a sort key that can be compared quickly with other keys.
        ///  
        internal XmlSortKey CreateSortKey(string s) {
            SortKey sortKey; 
            byte[] bytesKey; 
            int idx;
 
            //


            sortKey = Culture.CompareInfo.GetSortKey(s, this.compops); 

            // Create an XmlStringSortKey using the SortKey if possible 
        #if DEBUG 
            // In debug-only code, test other code path more frequently
            if (!this.upperFirst && this.descendingOrder) 
                return new XmlStringSortKey(sortKey, this.descendingOrder);
        #else
            if (!this.upperFirst)
                return new XmlStringSortKey(sortKey, this.descendingOrder); 
        #endif
 
            // Get byte buffer from SortKey and modify it 
            bytesKey = sortKey.KeyData;
            if (this.upperFirst && bytesKey.Length != 0) { 
                // By default lower-case is always sorted first for any locale (verified by empirical testing).
                // In order to place upper-case first, invert the case weights in the generated sort key.
                // Skip to case weight section (3rd weight section)
                idx = 0; 
                while (bytesKey[idx] != 1)
                    idx++; 
 
                do {
                    idx++; 
                }
                while (bytesKey[idx] != 1);

                // Invert all case weights (including terminating 0x1) 
                do {
                    idx++; 
                    bytesKey[idx] ^= 0xff; 
                }
                while (bytesKey[idx] != 0xfe); 
            }

            return new XmlStringSortKey(bytesKey, this.descendingOrder);
        } 

#if not_used 
        ///  
        /// Compare two strings with each other.  Return <0 if str1 sorts before str2, 0 if they're equal, and >0
        /// if str1 sorts after str2. 
        /// 
        internal int Compare(string str1, string str2) {
            CultureInfo cultinfo = Culture;
            int result; 

            if (UseOrdinalCompare) { 
                result = string.CompareOrdinal(str1, str2); 
                if (result < 0) result = -1;
                else if (result > 0) result = 1; 
            }
            else if (this.upperFirst) {
                // First compare case-insensitive, then break ties by considering case
                result = cultinfo.CompareInfo.Compare(str1, str2, this.compops | CompareOptions.IgnoreCase); 
                if (result == 0)
                    result = -cultinfo.CompareInfo.Compare(str1, str2, this.compops); 
            } 
            else {
                result = cultinfo.CompareInfo.Compare(str1, str2, this.compops); 
            }

            if (this.descendingOrder)
                result = -result; 

            return result; 
        } 

        ///  
        /// Return the index of str1 in str2, or -1 if str1 is not a substring of str2.
        /// 
        internal int IndexOf(string str1, string str2) {
            return Culture.CompareInfo.IndexOf(str1, str2, this.compops); 
        }
 
        ///  
        /// Return true if str1 ends with str2.
        ///  
        internal bool IsSuffix(string str1, string str2) {
            if (UseOrdinalCompare){
                if (str1.Length < str2.Length) {
                    return false; 
                } else {
                    return String.CompareOrdinal(str1, str1.Length - str2.Length, str2, 0, str2.Length) == 0; 
                } 
            }
            return Culture.CompareInfo.IsSuffix (str1, str2, this.compops); 
        }

        /// 
        /// Return true if str1 starts with str2. 
        /// 
        internal bool IsPrefix(string str1, string str2) { 
            if (UseOrdinalCompare) { 
                if (str1.Length < str2.Length) {
                    return false; 
                } else {
                    return String.CompareOrdinal(str1, 0, str2, 0, str2.Length) == 0;
                }
            } 
            return Culture.CompareInfo.IsPrefix (str1, str2, this.compops);
        } 
 
        private bool UseOrdinalCompare {
            get { return (this.compops & CompareOptions.Ordinal) != 0; } 
        }
#endif

 
        //-----------------------------------------------
        // Helper Functions 
        //----------------------------------------------- 

        private static int MakeLCID(int langid, int sortid) { 
            return (langid & 0xffff) | ((sortid & 0xf) << 16);
        }

        private static int GetLangID(int lcid) { 
            return (lcid & 0xffff);
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
//-----------------------------------------------------------------------------
 
using System.ComponentModel; 
using System.Diagnostics;
using System.Globalization; 
using System.IO;

namespace System.Xml.Xsl.Runtime {
    using Res = System.Xml.Utils.Res; 

    [EditorBrowsable(EditorBrowsableState.Never)] 
    public sealed class XmlCollation { 
        // lgid support for sort
        private const int deDE = 0x0407; 
        private const int huHU = 0x040E;
        private const int jaJP = 0x0411;
        private const int kaGE = 0x0437;
        private const int koKR = 0x0412; 
        private const int zhTW = 0x0404;
        private const int zhCN = 0x0804; 
        private const int zhHK = 0x0C04; 
        private const int zhSG = 0x1004;
        private const int zhMO = 0x1404; 
        private const int zhTWbopo = 0x030404;
        private const int deDEphon = 0x010407;
        private const int huHUtech = 0x01040e;
        private const int kaGEmode = 0x010437; 

        // Sort ID 
        private const int strksort = 0x02;      // Stroke 
        private const int unicsort = 0x01;      // Unicode
 
        // Options
        private const string ignoreCaseStr      = "IGNORECASE";
        private const string ignoreKanatypeStr  = "IGNOREKANATYPE";
        private const string ignoreNonspaceStr  = "IGNORENONSPACE"; 
        private const string ignoreSymbolsStr   = "IGNORESYMBOLS";
        private const string ignoreWidthStr     = "IGNOREWIDTH"; 
        private const string upperFirstStr      = "UPPERFIRST"; 
        private const string emptyGreatestStr   = "EMPTYGREATEST";
        private const string descendingOrderStr = "DESCENDINGORDER"; 
        private const string sortStr            = "SORT";

        private bool upperFirst;
        private bool emptyGreatest; 
        private bool descendingOrder;
        private CultureInfo cultinfo; 
        private CompareOptions compops; 

 
        //-----------------------------------------------
        // Constructors
        //-----------------------------------------------
 
        /// 
        /// By default, create a collation that uses the current thread's culture, and has no compare options set 
        ///  
        private XmlCollation() : this(null, CompareOptions.None) {
        } 

        /// 
        /// Construct a collation that uses the specified culture and compare options.
        ///  
        private XmlCollation(CultureInfo cultureInfo, CompareOptions compareOptions) {
            this.cultinfo = cultureInfo; 
            this.compops = compareOptions; 
        }
 

        //-----------------------------------------------
        // Create
        //----------------------------------------------- 

        ///  
        /// Singleton collation that sorts according to Unicode code points. 
        /// 
        private static XmlCollation cp = new XmlCollation(CultureInfo.InvariantCulture, CompareOptions.Ordinal); 
        internal static XmlCollation CodePointCollation {
            get { return cp; }
        }
 
        /// 
        /// This function is used in both parser and f&o library, so just strictly map valid literals to XmlCollation. 
        /// Set compare options one by one: 
        ///     0, false: no effect; 1, true: yes
        /// Disregard unrecognized options. 
        /// 
        internal static XmlCollation Create(string collationLiteral) {
            Debug.Assert(collationLiteral != null, "collation literal should not be null");
 
            if (collationLiteral == XmlReservedNs.NsCollCodePoint) {
                return CodePointCollation; 
            } 

            XmlCollation coll = new XmlCollation(); 
            Uri collationUri = new Uri(collationLiteral);

            string authority = collationUri.GetLeftPart(UriPartial.Authority);
            if (authority == XmlReservedNs.NsCollationBase) { 
                // Language
                // at least a '/' will be returned for Uri.LocalPath 
                string lang = collationUri.LocalPath.Substring(1); 
                if (lang.Length == 0) {
                    // Use default culture of current thread (cultinfo = null) 
                } else {
                    // Create culture from RFC 1766 string
                    try {
                        coll.cultinfo = new CultureInfo(lang); 
                    }
                    catch (ArgumentException) { 
                        throw new XslTransformException(Res.Coll_UnsupportedLanguage, lang); 
                    }
                } 
            } else if (collationUri.IsBaseOf(new Uri(XmlReservedNs.NsCollCodePoint))) {
                // language with codepoint collation is not allowed
                coll.compops = CompareOptions.Ordinal;
            } else { 
                // Unrecognized collation
                throw new XslTransformException(Res.Coll_Unsupported, collationLiteral); 
            } 

            // Sort & Compare option 
            // at least a '?' will be returned for Uri.Query if not empty
            string query = collationUri.Query;
            string sort = null;
 
            if (query.Length != 0) {
                foreach (string option in query.Substring(1).Split('&')) { 
                    string[] pair = option.Split('='); 

                    if (pair.Length != 2) 
                        throw new XslTransformException(Res.Coll_BadOptFormat, option);

                    string optionName = pair[0].ToUpper(CultureInfo.InvariantCulture);
                    string optionValue = pair[1].ToUpper(CultureInfo.InvariantCulture); 

                    if (optionName == sortStr) { 
                        sort = optionValue; 
                    }
                    else if (optionValue == "1" || optionValue == "TRUE") { 
                        switch (optionName) {
                        case ignoreCaseStr:        coll.compops |= CompareOptions.IgnoreCase; break;
                        case ignoreKanatypeStr:    coll.compops |= CompareOptions.IgnoreKanaType; break;
                        case ignoreNonspaceStr:    coll.compops |= CompareOptions.IgnoreNonSpace; break; 
                        case ignoreSymbolsStr:     coll.compops |= CompareOptions.IgnoreSymbols; break;
                        case ignoreWidthStr:       coll.compops |= CompareOptions.IgnoreWidth; break; 
                        case upperFirstStr:        coll.upperFirst = true; break; 
                        case emptyGreatestStr:     coll.emptyGreatest = true; break;
                        case descendingOrderStr:   coll.descendingOrder = true; break; 
                        default:
                            throw new XslTransformException(Res.Coll_UnsupportedOpt, pair[0]);
                        }
                    } 
                    else if (optionValue == "0" || optionValue == "FALSE") {
                        switch (optionName) { 
                        case ignoreCaseStr:        coll.compops &= ~CompareOptions.IgnoreCase; break; 
                        case ignoreKanatypeStr:    coll.compops &= ~CompareOptions.IgnoreKanaType; break;
                        case ignoreNonspaceStr:    coll.compops &= ~CompareOptions.IgnoreNonSpace; break; 
                        case ignoreSymbolsStr:     coll.compops &= ~CompareOptions.IgnoreSymbols; break;
                        case ignoreWidthStr:       coll.compops &= ~CompareOptions.IgnoreWidth; break;
                        case upperFirstStr:        coll.upperFirst = false; break;
                        case emptyGreatestStr:     coll.emptyGreatest = false; break; 
                        case descendingOrderStr:   coll.descendingOrder = false; break;
                        default: 
                            throw new XslTransformException(Res.Coll_UnsupportedOpt, pair[0]); 
                        }
                    } 
                    else {
                        throw new XslTransformException(Res.Coll_UnsupportedOptVal, pair[0], pair[1]);
                    }
                } 
            }
 
            // upperfirst option is only meaningful when not ignore case 
            if (coll.upperFirst && (coll.compops & CompareOptions.IgnoreCase) != 0)
                coll.upperFirst = false; 

            // other CompareOptions are only meaningful if Ordinal comparison is not being used
            if ((coll.compops & CompareOptions.Ordinal) != 0) {
                coll.compops = CompareOptions.Ordinal; 
                coll.upperFirst = false;
            } 
 
            // new cultureinfo based on alternate sorting option
            if (sort != null && coll.cultinfo != null) { 
                int lgid = GetLangID(coll.cultinfo.LCID);
                switch (sort) {
                case "bopo":
                    if (lgid == zhTW) { 
                        coll.cultinfo = new CultureInfo(zhTWbopo);
                    } 
                    break; 
                case "strk":
                    if (lgid == zhCN || lgid == zhHK || lgid == zhSG || lgid == zhMO) { 
                        coll.cultinfo = new CultureInfo(MakeLCID(coll.cultinfo.LCID, strksort));
                    }
                    break;
                case "uni": 
                    if (lgid == jaJP || lgid == koKR) {
                        coll.cultinfo = new CultureInfo(MakeLCID(coll.cultinfo.LCID, unicsort)); 
                    } 
                    break;
                case "phn": 
                    if (lgid == deDE) {
                        coll.cultinfo = new CultureInfo(deDEphon);
                    }
                    break; 
                case "tech":
                    if (lgid == huHU) { 
                        coll.cultinfo = new CultureInfo(huHUtech); 
                    }
                    break; 
                case "mod":
                    // ka-GE(Georgian - Georgia) Modern Sort: 0x00010437
                    if (lgid == kaGE) {
                        coll.cultinfo = new CultureInfo(kaGEmode); 
                    }
                    break; 
                case "pron": case "dict": case "trad": 
                    // es-ES(Spanish - Spain) Traditional: 0x0000040A
                    // They are removing 0x040a (Spanish Traditional sort) in NLS+. 
                    // So if you create 0x040a, it's just like 0x0c0a (Spanish International sort).
                    // Thus I don't handle it differently.
                    break;
                default: 
                    throw new XslTransformException(Res.Coll_UnsupportedSortOpt, sort);
                } 
            } 
            return coll;
        } 


        //-----------------------------------------------
        // Convert options to and from an integer 
        //-----------------------------------------------
 
        private const int FlagUpperFirst      = 0x1000; 
        private const int FlagEmptyGreatest   = 0x2000;
        private const int FlagDescendingOrder = 0x4000; 
        private const int CollationFlagsMask  = FlagUpperFirst | FlagEmptyGreatest | FlagDescendingOrder;

        private int GetOptions() {
            int result = (int)this.compops; 
            Debug.Assert((result & CollationFlagsMask) == 0, "CompareOptions and collation flags overlap");
 
            if (upperFirst) 
                result |= FlagUpperFirst;
 
            if (emptyGreatest)
                result |= FlagEmptyGreatest;

            if (descendingOrder) 
                result |= FlagDescendingOrder;
 
            return result; 
        }
 
        private void SetOptions(int options) {
            this.upperFirst       = (options & FlagUpperFirst     ) != 0;
            this.emptyGreatest    = (options & FlagEmptyGreatest  ) != 0;
            this.descendingOrder  = (options & FlagDescendingOrder) != 0; 
            this.compops = (CompareOptions)(options & ~CollationFlagsMask);
        } 
 

        //----------------------------------------------- 
        // Collection Support
        //-----------------------------------------------

        // Redefine Equals and GetHashCode methods, they are needed for UniqueList 
        public override bool Equals(object obj) {
            if (this == obj) { 
                return true; 
            }
 
            XmlCollation that = obj as XmlCollation;
            return that != null &&
                this.GetOptions() == that.GetOptions() &&
                object.Equals(this.cultinfo, that.cultinfo); 
        }
 
        public override int GetHashCode() { 
            int hashCode = this.GetOptions();
            if (this.cultinfo != null) { 
                hashCode ^= this.cultinfo.GetHashCode();
            }
            return hashCode;
        } 

 
        //----------------------------------------------- 
        // Serialization Support
        //----------------------------------------------- 

        // Denotes the current thread locale
        private const int LOCALE_CURRENT = -1;
 
        internal void GetObjectData(BinaryWriter writer) {
            // NOTE: For CultureInfo we serialize only LCID. It seems to suffice for our purposes. 
            Debug.Assert(this.cultinfo == null || this.cultinfo.Equals(new CultureInfo(this.cultinfo.LCID)), 
                "Cannot serialize CultureInfo correctly");
            writer.Write(this.cultinfo != null ? this.cultinfo.LCID : LOCALE_CURRENT); 
            writer.Write(this.GetOptions());
        }

        internal XmlCollation(BinaryReader reader) { 
            int lcid = reader.ReadInt32();
            this.cultinfo = (lcid != LOCALE_CURRENT) ? new CultureInfo(lcid) : null; 
            this.SetOptions(reader.ReadInt32()); 
        }
 

        //-----------------------------------------------
        // Compare Properties
        //----------------------------------------------- 

        internal bool EmptyGreatest { 
            get { return this.emptyGreatest; } 
        }
 
        internal bool DescendingOrder {
            get { return this.descendingOrder; }
        }
 
        internal CultureInfo Culture {
            get { 
                // Use default thread culture if this.cultinfo = null 
                if (this.cultinfo == null)
                    return CultureInfo.CurrentCulture; 

                return this.cultinfo;
            }
        } 

 
        //----------------------------------------------- 
        //
        //----------------------------------------------- 

        /// 
        /// Create a sort key that can be compared quickly with other keys.
        ///  
        internal XmlSortKey CreateSortKey(string s) {
            SortKey sortKey; 
            byte[] bytesKey; 
            int idx;
 
            //


            sortKey = Culture.CompareInfo.GetSortKey(s, this.compops); 

            // Create an XmlStringSortKey using the SortKey if possible 
        #if DEBUG 
            // In debug-only code, test other code path more frequently
            if (!this.upperFirst && this.descendingOrder) 
                return new XmlStringSortKey(sortKey, this.descendingOrder);
        #else
            if (!this.upperFirst)
                return new XmlStringSortKey(sortKey, this.descendingOrder); 
        #endif
 
            // Get byte buffer from SortKey and modify it 
            bytesKey = sortKey.KeyData;
            if (this.upperFirst && bytesKey.Length != 0) { 
                // By default lower-case is always sorted first for any locale (verified by empirical testing).
                // In order to place upper-case first, invert the case weights in the generated sort key.
                // Skip to case weight section (3rd weight section)
                idx = 0; 
                while (bytesKey[idx] != 1)
                    idx++; 
 
                do {
                    idx++; 
                }
                while (bytesKey[idx] != 1);

                // Invert all case weights (including terminating 0x1) 
                do {
                    idx++; 
                    bytesKey[idx] ^= 0xff; 
                }
                while (bytesKey[idx] != 0xfe); 
            }

            return new XmlStringSortKey(bytesKey, this.descendingOrder);
        } 

#if not_used 
        ///  
        /// Compare two strings with each other.  Return <0 if str1 sorts before str2, 0 if they're equal, and >0
        /// if str1 sorts after str2. 
        /// 
        internal int Compare(string str1, string str2) {
            CultureInfo cultinfo = Culture;
            int result; 

            if (UseOrdinalCompare) { 
                result = string.CompareOrdinal(str1, str2); 
                if (result < 0) result = -1;
                else if (result > 0) result = 1; 
            }
            else if (this.upperFirst) {
                // First compare case-insensitive, then break ties by considering case
                result = cultinfo.CompareInfo.Compare(str1, str2, this.compops | CompareOptions.IgnoreCase); 
                if (result == 0)
                    result = -cultinfo.CompareInfo.Compare(str1, str2, this.compops); 
            } 
            else {
                result = cultinfo.CompareInfo.Compare(str1, str2, this.compops); 
            }

            if (this.descendingOrder)
                result = -result; 

            return result; 
        } 

        ///  
        /// Return the index of str1 in str2, or -1 if str1 is not a substring of str2.
        /// 
        internal int IndexOf(string str1, string str2) {
            return Culture.CompareInfo.IndexOf(str1, str2, this.compops); 
        }
 
        ///  
        /// Return true if str1 ends with str2.
        ///  
        internal bool IsSuffix(string str1, string str2) {
            if (UseOrdinalCompare){
                if (str1.Length < str2.Length) {
                    return false; 
                } else {
                    return String.CompareOrdinal(str1, str1.Length - str2.Length, str2, 0, str2.Length) == 0; 
                } 
            }
            return Culture.CompareInfo.IsSuffix (str1, str2, this.compops); 
        }

        /// 
        /// Return true if str1 starts with str2. 
        /// 
        internal bool IsPrefix(string str1, string str2) { 
            if (UseOrdinalCompare) { 
                if (str1.Length < str2.Length) {
                    return false; 
                } else {
                    return String.CompareOrdinal(str1, 0, str2, 0, str2.Length) == 0;
                }
            } 
            return Culture.CompareInfo.IsPrefix (str1, str2, this.compops);
        } 
 
        private bool UseOrdinalCompare {
            get { return (this.compops & CompareOptions.Ordinal) != 0; } 
        }
#endif

 
        //-----------------------------------------------
        // Helper Functions 
        //----------------------------------------------- 

        private static int MakeLCID(int langid, int sortid) { 
            return (langid & 0xffff) | ((sortid & 0xf) << 16);
        }

        private static int GetLangID(int lcid) { 
            return (lcid & 0xffff);
        } 
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK