The Labs \ Source Viewer \ SSCLI \ System.Globalization \ CompareInfo

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. ////////////////////////////////////////////////////////////////////////////
  16. //
  17. // Class: CompareInfo
  18. //
  19. //
  20. // Purpose: This class implements a set of methods for comparing
  21. // strings.
  22. //
  23. // Date: August 12, 1998
  24. //
  25. ////////////////////////////////////////////////////////////////////////////
  26. namespace System.Globalization
  27. {
  28.    
  29.     //
  30.     // We're dependent on the m_pSortingTable getting created when an instance of the
  31.     // class is initialized (through a call to InitializeCompareInfo). When in
  32.     // native, we assume that the table has already been allocated. we may decide
  33.     // to delay-allocate any of the tables (as we may do for US English)//
  34.     // System.Globalization.SortKey also uses the m_pSortingTables. Currently the only
  35.     // way to get a SortKey is to call through CompareInfo, which means that the table
  36.     // has already been initialized. If this invariant changes, SortKey's constructor
  37.     // needs to call InitializedSortingTable (which can safely be called multiple times
  38.     // for the same locale.)
  39.     //
  40.    
  41.     using System;
  42.     using System.Collections;
  43.     using System.Reflection;
  44.     using System.Runtime.Serialization;
  45.     using System.Runtime.CompilerServices;
  46.     using System.Runtime.ConstrainedExecution;
  47.     using System.Threading;
  48.     using System.Security.Permissions;
  49.     using System.Runtime.InteropServices;
  50.     using Microsoft.Win32;
  51.    
  52.     //
  53.     // Options can be used during string comparison.
  54.     //
  55.     // Native implementation (COMNlsInfo.cpp & SortingTable.cpp) relies on the values of these,
  56.     // If you change the values below, be sure to change the values in native part as well.
  57.     //
  58.    
  59.    
  60.     [Flags(), Serializable()]
  61.     [System.Runtime.InteropServices.ComVisible(true)]
  62.     public enum CompareOptions
  63.     {
  64.        
  65.         None = 0,
  66.        
  67.         IgnoreCase = 1,
  68.        
  69.         IgnoreNonSpace = 2,
  70.        
  71.         IgnoreSymbols = 4,
  72.        
  73.         IgnoreKanaType = 8,
  74.         // ignore kanatype
  75.         IgnoreWidth = 16,
  76.         // ignore width
  77.         OrdinalIgnoreCase = 268435456,
  78.         // This flag can not be used with other flags.
  79.         StringSort = 536870912,
  80.         // use string sort method
  81.         Ordinal = 1073741824
  82.         // This flag can not be used with other flags.
  83.         // StopOnNull = 0x10000000,
  84.        
  85.         // StopOnNull is defined in SortingTable.h, but we didn't enable this option here.
  86.         // Do not use this value for other flags accidentally.
  87.     }
  88.    
  89.    
  90.     [Serializable()]
  91.     [System.Runtime.InteropServices.ComVisible(true)]
  92.     public class CompareInfo : IDeserializationCallback
  93.     {
  94.        
  95.         // Mask used to check if IndexOf()/LastIndexOf()/IsPrefix()/IsPostfix() has the right flags.
  96.         private const CompareOptions ValidIndexMaskOffFlags = ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType);
  97.         // Mask used to check if Compare() has the right flags.
  98.         private const CompareOptions ValidCompareMaskOffFlags = ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType | CompareOptions.StringSort);
  99.         // Mask used to check if GetHashCodeOfString() has the right flags.
  100.         private const CompareOptions ValidHashCodeOfStringMaskOffFlags = ~(CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreWidth | CompareOptions.IgnoreKanaType);
  101.        
  102.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  103.         unsafe static internal extern byte[] nativeCreateSortKey(void* pSortingFile, string pString, int dwFlags, int win32LCID);
  104.        
  105.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  106.         unsafe static internal extern int nativeGetGlobalizedHashCode(void* pSortingFile, string pString, int dwFlags, int win32LCID);
  107.        
  108.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  109.         unsafe static internal extern bool nativeIsSortable(void* pSortingFile, string pString);
  110.        
  111.         // <SyntheticSupport/>
  112.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  113.         static internal extern int nativeCompareString(int lcid, string string1, int offset1, int length1, string string2, int offset2, int length2, int flags);
  114.         // Private object for locking instead of locking on a public type for SQL reliability work.
  115.         private static object s_InternalSyncObject;
  116.         private static object InternalSyncObject {
  117.             get {
  118.                 if (s_InternalSyncObject == null) {
  119.                     object o = new object();
  120.                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  121.                 }
  122.                 return s_InternalSyncObject;
  123.             }
  124.         }
  125.        
  126. /*=================================GetCompareInfo==========================
  127.         **Action: Get the CompareInfo constructed from the data table in the specified assembly for the specified culture.
  128.         **      The purpose of this method is to provide versioning for CompareInfo tables.
  129.         **      If you pass Assembly which contains different sorting table, you will sort your strings using the data
  130.         **      in the assembly.
  131.         **Returns: The CompareInfo for the specified culture.
  132.         **Arguments:
  133.         **  culture    the ID of the culture
  134.         **  assembly  the assembly which contains the sorting table.
  135.         **Exceptions:
  136.         **  ArugmentNullException when the assembly is null
  137.         **  ArgumentException if culture is invalid.
  138.         ============================================================================*/       
  139.        
  140. /* The design goal here is that we can still provide version even when the underlying algorithm for CompareInfo
  141.             is totally changed in the future.
  142.             In the case that the algorithm for CompareInfo is changed, we can use this method to
  143.             provide the old algorithm for the old tables.  The idea is to change the implementation for GetCompareInfo()
  144.             to something like:
  145.               1. Check the ID of the assembly.
  146.               2. If the assembly needs old code, create an instance of the old CompareInfo class. The name of CompareInfo
  147.                   will be like CompareInfoVersion1 and extends from CompareInfo.
  148.               3. Otherwise, create an instance of the current CompareInfo.
  149.             The CompareInfo ctor always provides the implementation for the current data table.
  150.         */       
  151.        
  152.        
  153.         public static CompareInfo GetCompareInfo(int culture, Assembly assembly)
  154.         {
  155.             // Parameter checking.
  156.             if (assembly == null) {
  157.                 throw new ArgumentNullException("assembly");
  158.             }
  159.            
  160.             if (CultureTableRecord.IsCustomCultureId(culture)) {
  161.                 // Customized culture cannot be created by the LCID.
  162.                 throw new ArgumentException(Environment.GetResourceString("Argument_CustomCultureCannotBePassedByNumber", "culture"));
  163.             }
  164.             if (assembly != typeof(object).Module.Assembly) {
  165.                 throw new ArgumentException(Environment.GetResourceString("Argument_OnlyMscorlib"));
  166.             }
  167.            
  168.             // culture is verified to see if it is valid when CompareInfo is constructed.
  169.            
  170.             GlobalizationAssembly ga = GlobalizationAssembly.GetGlobalizationAssembly(assembly);
  171.             object compInfo = ga.compareInfoCache[culture];
  172.             if (compInfo == null) {
  173.                 lock (InternalSyncObject) {
  174.                     //
  175.                     // Re-check again to make sure that no one has created the CompareInfo for the culture yet before the current
  176.                     // thread enters this sync block.
  177.                     //
  178.                     if ((compInfo = ga.compareInfoCache[culture]) == null) {
  179.                         compInfo = new CompareInfo(ga, culture);
  180.                         System.Threading.Thread.MemoryBarrier();
  181.                         ga.compareInfoCache[culture] = compInfo;
  182.                     }
  183.                 }
  184.             }
  185.            
  186.             return ((CompareInfo)compInfo);
  187.         }
  188.        
  189.        
  190.         //
  191.         // GetCompareInfoByName get CompareInfo object using the name. it is the shared code
  192.         // between GetCompareInfo(name) and GetCompareInfo(name, assembly)
  193.         //
  194.        
  195.         private const int TraditionalChineseCultureId = 31748;
  196.         private const int HongKongCultureId = 3076;
  197.        
  198.         private static CompareInfo GetCompareInfoByName(string name, Assembly assembly)
  199.         {
  200.             CultureInfo cultureInfo = CultureInfo.GetCultureInfo(name);
  201.             if (cultureInfo.IsNeutralCulture && !CultureTableRecord.IsCustomCultureId(cultureInfo.cultureID)) {
  202.                 if (cultureInfo.cultureID == TraditionalChineseCultureId)
  203.                     cultureInfo = CultureInfo.GetCultureInfo(HongKongCultureId);
  204.                 else
  205.                     cultureInfo = CultureInfo.GetCultureInfo(cultureInfo.CompareInfoId);
  206.             }
  207.            
  208.             CompareInfo compareInfo;
  209.            
  210.             if (assembly != null)
  211.                 compareInfo = GetCompareInfo(cultureInfo.CompareInfoId, assembly);
  212.             else
  213.                 compareInfo = GetCompareInfo(cultureInfo.CompareInfoId);
  214.            
  215.             // Compare info name is known by the cultureInfo
  216.             compareInfo.m_name = cultureInfo.SortName;
  217.            
  218.             return compareInfo;
  219.         }
  220.        
  221.        
  222. /*=================================GetCompareInfo==========================
  223.         **Action: Get the CompareInfo constructed from the data table in the specified assembly for the specified culture.
  224.         **      The purpose of this method is to provide version for CompareInfo tables.
  225.         **Returns: The CompareInfo for the specified culture.
  226.         **Arguments:
  227.         **  name    the name of the culture
  228.         **  assembly  the assembly which contains the sorting table.
  229.         **Exceptions:
  230.         **  ArugmentNullException when the assembly is null
  231.         **  ArgumentException if name is invalid.
  232.         ============================================================================*/       
  233.        
  234.         public static CompareInfo GetCompareInfo(string name, Assembly assembly)
  235.         {
  236.             if (name == null || assembly == null) {
  237.                 throw new ArgumentNullException(name == null ? "name" : "assembly");
  238.             }
  239.            
  240.             if (assembly != typeof(object).Module.Assembly) {
  241.                 throw new ArgumentException(Environment.GetResourceString("Argument_OnlyMscorlib"));
  242.             }
  243.            
  244.             return GetCompareInfoByName(name, assembly);
  245.         }
  246.        
  247. /*=================================GetCompareInfo==========================
  248.         **Action: Get the CompareInfo for the specified culture.
  249.         ** This method is provided for ease of integration with NLS-based software.
  250.         **Returns: The CompareInfo for the specified culture.
  251.         **Arguments:
  252.         **  culture    the ID of the culture.
  253.         **Exceptions:
  254.         **  ArgumentException if culture is invalid.       
  255.         **Notes:
  256.         **  We optimize in the default case.  We don't go thru the GlobalizationAssembly hashtable.
  257.         **  Instead, we access the m_defaultInstance directly.
  258.         ============================================================================*/       
  259.        
  260.         public static CompareInfo GetCompareInfo(int culture)
  261.         {
  262.            
  263.             if (CultureTableRecord.IsCustomCultureId(culture)) {
  264.                 // Customized culture cannot be created by the LCID.
  265.                 throw new ArgumentException(Environment.GetResourceString("Argument_CustomCultureCannotBePassedByNumber", "culture"));
  266.             }
  267.            
  268.             // culture is verified to see if it is valid when CompareInfo is constructed.
  269.             object compInfo = GlobalizationAssembly.DefaultInstance.compareInfoCache[culture];
  270.             if (compInfo == null) {
  271.                 lock (InternalSyncObject) {
  272.                     //
  273.                     // Re-check again to make sure that no one has created the CompareInfo for the culture yet before the current
  274.                     // thread enters this sync block.
  275.                     //
  276.                     if ((compInfo = GlobalizationAssembly.DefaultInstance.compareInfoCache[culture]) == null) {
  277.                         compInfo = new CompareInfo(GlobalizationAssembly.DefaultInstance, culture);
  278.                         System.Threading.Thread.MemoryBarrier();
  279.                         GlobalizationAssembly.DefaultInstance.compareInfoCache[culture] = compInfo;
  280.                     }
  281.                 }
  282.             }
  283.             return ((CompareInfo)compInfo);
  284.         }
  285.        
  286. /*=================================GetCompareInfo==========================
  287.         **Action: Get the CompareInfo for the specified culture.
  288.         **Returns: The CompareInfo for the specified culture.
  289.         **Arguments:
  290.         **  name    the name of the culture.
  291.         **Exceptions:
  292.         **  ArgumentException if name is invalid.
  293.         ============================================================================*/       
  294.        
  295.         public static CompareInfo GetCompareInfo(string name)
  296.         {
  297.             if (name == null) {
  298.                 throw new ArgumentNullException("name");
  299.             }
  300.            
  301.             return GetCompareInfoByName(name, null);
  302.         }
  303.        
  304.         [System.Runtime.InteropServices.ComVisible(false)]
  305.         public static bool IsSortable(char ch)
  306.         {
  307.             return (IsSortable(ch.ToString()));
  308.         }
  309.        
  310.         [System.Runtime.InteropServices.ComVisible(false)]
  311.         public static bool IsSortable(string text)
  312.         {
  313.             if (text == null) {
  314.                 // A null param is invalid here.
  315.                 throw new ArgumentNullException("text");
  316.             }
  317.            
  318.             if (0 == text.Length) {
  319.                 // A zero length string is not invalid, but it is also not sortable.
  320.                 return (false);
  321.             }
  322.            
  323.             unsafe {
  324.                 return (nativeIsSortable(CultureInfo.InvariantCulture.CompareInfo.m_pSortingTable, text));
  325.             }
  326.         }
  327.        
  328.         #region Serialization
  329.         private int win32LCID;
  330.         // mapped sort culture id of this instance
  331.         private int culture;
  332.         // the culture ID used to create this instance.
  333.         [OnDeserializing()]
  334.         private void OnDeserializing(StreamingContext ctx)
  335.         {
  336.             this.culture = -1;
  337.             this.m_sortingLCID = -1;
  338.         }
  339.        
  340.         unsafe private void OnDeserialized()
  341.         {
  342.             BCLDebug.Assert(this.culture >= 0, "[CompareInfo.OnDeserialized] - culture >= 0");
  343.            
  344.             // Get the Win32 LCID used to create NativeCompareInfo, which only takes Win32 LCID.
  345.             if (m_sortingLCID <= 0) {
  346.                 m_sortingLCID = GetSortingLCID(this.culture);
  347.             }
  348.             if (m_pSortingTable == null && !IsSynthetic) {
  349.                 m_pSortingTable = InitializeCompareInfo(GlobalizationAssembly.DefaultInstance.pNativeGlobalizationAssembly, this.m_sortingLCID);
  350.             }
  351.             BCLDebug.Assert(IsSynthetic || m_pSortingTable != null, "m_pSortingTable != null");
  352.             // m_name is intialized later if it not exist in the serialization stream
  353.         }
  354.        
  355.        
  356.         [OnDeserialized()]
  357.         private void OnDeserialized(StreamingContext ctx)
  358.         {
  359.             OnDeserialized();
  360.         }
  361.        
  362.         [OnSerializing()]
  363.         private void OnSerializing(StreamingContext ctx)
  364.         {
  365.             win32LCID = m_sortingLCID;
  366.         }
  367.         #endregion Serialization
  368.        
  369.         ///////////////////////////----- Name -----/////////////////////////////////
  370.         //
  371.         // Returns the name of the culture (well actually, of the sort).
  372.         // Very important for providing a non-LCID way of identifying
  373.         // what the sort is.
  374.         //
  375.         ////////////////////////////////////////////////////////////////////////
  376.        
  377.         [System.Runtime.InteropServices.ComVisible(false)]
  378.         public virtual string Name {
  379.             get {
  380.                 if (m_name == null) {
  381.                     m_name = CultureInfo.GetCultureInfo(culture).SortName;
  382.                 }
  383.                
  384.                 return (m_name);
  385.             }
  386.         }
  387.        
  388.         internal void SetName(string name)
  389.         {
  390.             m_name = name;
  391.         }
  392.        
  393.         static internal void ClearDefaultAssemblyCache()
  394.         {
  395.             lock (InternalSyncObject) {
  396.                 GlobalizationAssembly.DefaultInstance.compareInfoCache = new Hashtable(4);
  397.             }
  398.         }
  399.        
  400.        
  401.         internal CultureTableRecord CultureTableRecord {
  402.             get {
  403.                 if (m_cultureTableRecord == null) {
  404.                     m_cultureTableRecord = CultureInfo.GetCultureInfo(this.m_sortingLCID).m_cultureTableRecord;
  405.                 }
  406.                
  407.                 return m_cultureTableRecord;
  408.             }
  409.         }
  410.        
  411.         // <SyntheticSupport/>
  412.         private bool IsSynthetic {
  413.             get { return CultureTableRecord.IsSynthetic; }
  414.         }
  415.        
  416.         //
  417.         // pSortingTable is a 32-bit pointer value pointing to a native C++ SortingTable object.
  418.         //
  419.         [NonSerialized()]
  420.         unsafe internal void* m_pSortingTable;
  421.         [NonSerialized()]
  422.         private int m_sortingLCID;
  423.         // mapped sort culture id of this instance
  424.         [NonSerialized()]
  425.         private CultureTableRecord m_cultureTableRecord;
  426.        
  427.         [OptionalField(VersionAdded = 2)]
  428.         private string m_name = null;
  429.         // The name of the culture of this instance
  430.        
  431.        
  432.         ////////////////////////////////////////////////////////////////////////
  433.         //
  434.         // CompareInfo Constructor
  435.         //
  436.         //
  437.         ////////////////////////////////////////////////////////////////////////
  438.        
  439.        
  440.         // Constructs an instance that most closely corresponds to the NLS locale
  441.         // identifier.
  442.         unsafe internal CompareInfo(GlobalizationAssembly ga, int culture)
  443.         {
  444.             if (culture < 0) {
  445.                 throw new ArgumentOutOfRangeException("culture", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  446.             }
  447.             // Get the Win32 LCID used to create NativeCompareInfo, which only takes Win32 LCID.
  448.             this.m_sortingLCID = GetSortingLCID(culture);
  449.            
  450.             // If version support is enabled, InitializeCompareInfo should use ga instead of getting the default
  451.             // instance.
  452.            
  453.             // Call to the native side to create/get the corresponding native C++ SortingTable for this culture.
  454.             // The returned value is a 32-bit pointer to the native C++ SortingTable instance.
  455.             // We cache this pointer so that we can call methods of the SortingTable directly.
  456.             if (!IsSynthetic) {
  457.                 m_pSortingTable = InitializeCompareInfo(GlobalizationAssembly.DefaultInstance.pNativeGlobalizationAssembly, this.m_sortingLCID);
  458.             }
  459.             // Since this.m_sortingLCID can be different from the passed-in culture in the case of neutral cultures, store the culture ID in a different place.
  460.             this.culture = culture;
  461.            
  462.         }
  463.        
  464.        
  465.         internal int GetSortingLCID(int culture)
  466.         {
  467.             int sortingLCID = 0;
  468.             //
  469.             // Verify that this is a valid culture.
  470.             //
  471.             CultureInfo cultureObj = CultureInfo.GetCultureInfo(culture);
  472.            
  473.            
  474.             sortingLCID = cultureObj.CompareInfoId;
  475.            
  476.             int sortID = CultureInfo.GetSortID(culture);
  477.             if (sortID != 0) {
  478.                 // Need to verify if the Sort ID is valid.
  479.                 if (!cultureObj.m_cultureTableRecord.IsValidSortID(sortID)) {
  480.                     throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureNotSupported"), culture), "culture");
  481.                 }
  482.                 // This is an alterinative sort LCID. Hey man, don't forget to take your SORTID with you.
  483.                 sortingLCID |= sortID << 16;
  484.             }
  485.             return (sortingLCID);
  486.            
  487.         }
  488.        
  489.        
  490.         ////////////////////////////////////////////////////////////////////////
  491.         //
  492.         // Compare
  493.         //
  494.         // Compares the two strings with the given options. Returns 0 if the
  495.         // two strings are equal, a number less than 0 if string1 is less
  496.         // than string2, and a number greater than 0 if string1 is greater
  497.         // than string2.
  498.         //
  499.         ////////////////////////////////////////////////////////////////////////
  500.        
  501.        
  502.         public virtual int Compare(string string1, string string2)
  503.         {
  504.             return (Compare(string1, string2, CompareOptions.None));
  505.         }
  506.        
  507.        
  508.         unsafe public virtual int Compare(string string1, string string2, CompareOptions options)
  509.         {
  510.            
  511.             if (options == CompareOptions.OrdinalIgnoreCase) {
  512.                 return String.Compare(string1, string2, StringComparison.OrdinalIgnoreCase);
  513.             }
  514.            
  515.             // Verify the options before we do any real comparison.
  516.             if ((options & CompareOptions.Ordinal) != 0) {
  517.                 if (options == CompareOptions.Ordinal) {
  518.                     //Our paradigm is that null sorts less than any other string and
  519.                     //that two nulls sort as equal.
  520.                     if (string1 == null) {
  521.                         if (string2 == null) {
  522.                             return (0);
  523.                             // Equal
  524.                         }
  525.                         return (-1);
  526.                         // null < non-null
  527.                     }
  528.                     if (string2 == null) {
  529.                         return (1);
  530.                         // non-null > null
  531.                     }
  532.                    
  533.                     return String.nativeCompareOrdinal(string1, string2, false);
  534.                 }
  535.                 else {
  536.                     throw new ArgumentException(Environment.GetResourceString("Argument_CompareOptionOrdinal"), "options");
  537.                 }
  538.             }
  539.             if ((options & ValidCompareMaskOffFlags) != 0) {
  540.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  541.             }
  542.            
  543.             //Our paradigm is that null sorts less than any other string and
  544.             //that two nulls sort as equal.
  545.             if (string1 == null) {
  546.                 if (string2 == null) {
  547.                     return (0);
  548.                     // Equal
  549.                 }
  550.                 return (-1);
  551.                 // null < non-null
  552.             }
  553.             if (string2 == null) {
  554.                 return (1);
  555.                 // non-null > null
  556.             }
  557.            
  558.            
  559.             return (Compare(m_pSortingTable, this.m_sortingLCID, string1, string2, options));
  560.         }
  561.        
  562.         // This native method will check the parameters and validate them accordingly.
  563.         // COMNlsInfo::Compare
  564.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  565.         unsafe private static extern int Compare(void* pSortingTable, int sortingLCID, string string1, string string2, CompareOptions options);
  566.        
  567.        
  568.         ////////////////////////////////////////////////////////////////////////
  569.         //
  570.         // Compare
  571.         //
  572.         // Compares the specified regions of the two strings with the given
  573.         // options.
  574.         // Returns 0 if the two strings are equal, a number less than 0 if
  575.         // string1 is less than string2, and a number greater than 0 if
  576.         // string1 is greater than string2.
  577.         //
  578.         ////////////////////////////////////////////////////////////////////////
  579.        
  580.        
  581.         unsafe public virtual int Compare(string string1, int offset1, int length1, string string2, int offset2, int length2)
  582.         {
  583.             return Compare(string1, offset1, length1, string2, offset2, length2, 0);
  584.         }
  585.        
  586.        
  587.         unsafe public virtual int Compare(string string1, int offset1, string string2, int offset2, CompareOptions options)
  588.         {
  589.             return Compare(string1, offset1, string1 == null ? 0 : string1.Length - offset1, string2, offset2, string2 == null ? 0 : string2.Length - offset2, options);
  590.         }
  591.        
  592.        
  593.         unsafe public virtual int Compare(string string1, int offset1, string string2, int offset2)
  594.         {
  595.             return Compare(string1, offset1, string2, offset2, 0);
  596.         }
  597.        
  598.        
  599.         unsafe public virtual int Compare(string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options)
  600.         {
  601.             if (options == CompareOptions.OrdinalIgnoreCase) {
  602.                 int result = String.Compare(string1, offset1, string2, offset2, length1 < length2 ? length1 : length2, StringComparison.OrdinalIgnoreCase);
  603.                 if ((length1 != length2) && result == 0)
  604.                     return (length1 > length2 ? 1 : -1);
  605.                 return (result);
  606.             }
  607.            
  608.             // Verifiy inputs
  609.             if (length1 < 0 || length2 < 0) {
  610.                 throw new ArgumentOutOfRangeException((length1 < 0) ? "length1" : "length2", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  611.             }
  612.             if (offset1 < 0 || offset2 < 0) {
  613.                 throw new ArgumentOutOfRangeException((offset1 < 0) ? "offset1" : "offset2", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  614.             }
  615.             if (offset1 > (string1 == null ? 0 : string1.Length) - length1) {
  616.                 throw new ArgumentOutOfRangeException("string1", Environment.GetResourceString("ArgumentOutOfRange_OffsetLength"));
  617.             }
  618.             if (offset2 > (string2 == null ? 0 : string2.Length) - length2) {
  619.                 throw new ArgumentOutOfRangeException("string2", Environment.GetResourceString("ArgumentOutOfRange_OffsetLength"));
  620.             }
  621.             if ((options & CompareOptions.Ordinal) != 0) {
  622.                 if (options == CompareOptions.Ordinal) {
  623.                     //
  624.                     // Check for the null case.
  625.                     //
  626.                     if (string1 == null) {
  627.                         if (string2 == null) {
  628.                             return (0);
  629.                         }
  630.                         return (-1);
  631.                     }
  632.                     if (string2 == null) {
  633.                         return (1);
  634.                     }
  635.                    
  636.                     int result = String.nativeCompareOrdinalEx(string1, offset1, string2, offset2, (length1 < length2 ? length1 : length2));
  637.                     if ((length1 != length2) && result == 0) {
  638.                         return (length1 > length2 ? 1 : -1);
  639.                     }
  640.                     return (result);
  641.                 }
  642.                 else {
  643.                     throw new ArgumentException(Environment.GetResourceString("Argument_CompareOptionOrdinal"), "options");
  644.                 }
  645.             }
  646.             if ((options & ValidCompareMaskOffFlags) != 0) {
  647.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  648.             }
  649.            
  650.             //
  651.             // Check for the null case.
  652.             //
  653.             if (string1 == null) {
  654.                 if (string2 == null) {
  655.                     return (0);
  656.                 }
  657.                 return (-1);
  658.             }
  659.             if (string2 == null) {
  660.                 return (1);
  661.             }
  662.            
  663.            
  664.             // Call native code to do comparison
  665.             return (CompareRegion(m_pSortingTable, this.m_sortingLCID, string1, offset1, length1, string2, offset2, length2, options));
  666.         }
  667.        
  668.         // This native method will check the parameters and validate them accordingly.
  669.         // Native method: COMNlsInfo::CompareRegion
  670.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  671.         unsafe private static extern int CompareRegion(void* pSortingTable, int sortingLCID, string string1, int offset1, int length1, string string2, int offset2, int length2, CompareOptions options);
  672.        
  673.        
  674.        
  675.        
  676.        
  677.         ////////////////////////////////////////////////////////////////////////
  678.         //
  679.         // IsPrefix
  680.         //
  681.         // Determines whether prefix is a prefix of string. If prefix equals
  682.         // String.Empty, true is returned.
  683.         //
  684.         ////////////////////////////////////////////////////////////////////////
  685.        
  686.        
  687.         unsafe public virtual bool IsPrefix(string source, string prefix, CompareOptions options)
  688.         {
  689.             if (source == null || prefix == null) {
  690.                 throw new ArgumentNullException((source == null ? "source" : "prefix"), Environment.GetResourceString("ArgumentNull_String"));
  691.             }
  692.             int prefixLen = prefix.Length;
  693.            
  694.             if (prefixLen == 0) {
  695.                 return (true);
  696.             }
  697.            
  698.             if (options == CompareOptions.OrdinalIgnoreCase) {
  699.                 return source.StartsWith(prefix, StringComparison.OrdinalIgnoreCase);
  700.             }
  701.            
  702.             if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal)) {
  703.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  704.             }
  705.            
  706.            
  707.             return (nativeIsPrefix(m_pSortingTable, this.m_sortingLCID, source, prefix, options));
  708.         }
  709.        
  710.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  711.         unsafe private static extern bool nativeIsPrefix(void* pSortingTable, int sortingLCID, string source, string prefix, CompareOptions options);
  712.        
  713.        
  714.         public virtual bool IsPrefix(string source, string prefix)
  715.         {
  716.             return (IsPrefix(source, prefix, 0));
  717.         }
  718.        
  719.        
  720.         ////////////////////////////////////////////////////////////////////////
  721.         //
  722.         // IsSuffix
  723.         //
  724.         // Determines whether suffix is a suffix of string. If suffix equals
  725.         // String.Empty, true is returned.
  726.         //
  727.         ////////////////////////////////////////////////////////////////////////
  728.        
  729.        
  730.         unsafe public virtual bool IsSuffix(string source, string suffix, CompareOptions options)
  731.         {
  732.             if (source == null || suffix == null) {
  733.                 throw new ArgumentNullException((source == null ? "source" : "suffix"), Environment.GetResourceString("ArgumentNull_String"));
  734.             }
  735.             int suffixLen = suffix.Length;
  736.            
  737.             if (suffixLen == 0) {
  738.                 return (true);
  739.             }
  740.            
  741.             if (options == CompareOptions.OrdinalIgnoreCase) {
  742.                 return source.EndsWith(suffix, StringComparison.OrdinalIgnoreCase);
  743.             }
  744.            
  745.             if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal)) {
  746.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  747.             }
  748.            
  749.            
  750.             return (nativeIsSuffix(m_pSortingTable, this.m_sortingLCID, source, suffix, options));
  751.         }
  752.        
  753.        
  754.         public virtual bool IsSuffix(string source, string suffix)
  755.         {
  756.             return (IsSuffix(source, suffix, 0));
  757.         }
  758.        
  759.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  760.         unsafe private static extern bool nativeIsSuffix(void* pSortingTable, int sortingLCID, string source, string prefix, CompareOptions options);
  761.        
  762.         ////////////////////////////////////////////////////////////////////////
  763.         //
  764.         // IndexOf
  765.         //
  766.         // Returns the first index where value is found in string. The
  767.         // search starts from startIndex and ends at endIndex. Returns -1 if
  768.         // the specified value is not found. If value equals String.Empty,
  769.         // startIndex is returned. Throws IndexOutOfRange if startIndex or
  770.         // endIndex is less than zero or greater than the length of string.
  771.         // Throws ArgumentException if value is null.
  772.         //
  773.         ////////////////////////////////////////////////////////////////////////
  774.        
  775.        
  776.         unsafe public virtual int IndexOf(string source, char value)
  777.         {
  778.             if (source == null)
  779.                 throw new ArgumentNullException("source");
  780.            
  781.             return IndexOf(source, value, 0, source.Length, CompareOptions.None);
  782.         }
  783.        
  784.        
  785.         unsafe public virtual int IndexOf(string source, string value)
  786.         {
  787.             if (source == null)
  788.                 throw new ArgumentNullException("source");
  789.            
  790.             return IndexOf(source, value, 0, source.Length, CompareOptions.None);
  791.         }
  792.        
  793.        
  794.         unsafe public virtual int IndexOf(string source, char value, CompareOptions options)
  795.         {
  796.             if (source == null)
  797.                 throw new ArgumentNullException("source");
  798.            
  799.             return IndexOf(source, value, 0, source.Length, options);
  800.         }
  801.        
  802.        
  803.         unsafe public virtual int IndexOf(string source, string value, CompareOptions options)
  804.         {
  805.             if (source == null)
  806.                 throw new ArgumentNullException("source");
  807.            
  808.             return IndexOf(source, value, 0, source.Length, options);
  809.         }
  810.        
  811.        
  812.         unsafe public virtual int IndexOf(string source, char value, int startIndex)
  813.         {
  814.             if (source == null)
  815.                 throw new ArgumentNullException("source");
  816.            
  817.             return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None);
  818.         }
  819.        
  820.        
  821.         unsafe public virtual int IndexOf(string source, string value, int startIndex)
  822.         {
  823.             if (source == null)
  824.                 throw new ArgumentNullException("source");
  825.            
  826.             return IndexOf(source, value, startIndex, source.Length - startIndex, CompareOptions.None);
  827.         }
  828.        
  829.        
  830.         unsafe public virtual int IndexOf(string source, char value, int startIndex, CompareOptions options)
  831.         {
  832.             if (source == null)
  833.                 throw new ArgumentNullException("source");
  834.            
  835.             return IndexOf(source, value, startIndex, source.Length - startIndex, options);
  836.         }
  837.        
  838.        
  839.         unsafe public virtual int IndexOf(string source, string value, int startIndex, CompareOptions options)
  840.         {
  841.             if (source == null)
  842.                 throw new ArgumentNullException("source");
  843.            
  844.             return IndexOf(source, value, startIndex, source.Length - startIndex, options);
  845.         }
  846.        
  847.        
  848.         unsafe public virtual int IndexOf(string source, char value, int startIndex, int count)
  849.         {
  850.             return IndexOf(source, value, startIndex, count, CompareOptions.None);
  851.         }
  852.        
  853.        
  854.         unsafe public virtual int IndexOf(string source, string value, int startIndex, int count)
  855.         {
  856.             return IndexOf(source, value, startIndex, count, CompareOptions.None);
  857.         }
  858.        
  859.        
  860.         unsafe public virtual int IndexOf(string source, char value, int startIndex, int count, CompareOptions options)
  861.         {
  862.             // Validate inputs
  863.             if (source == null)
  864.                 throw new ArgumentNullException("source");
  865.            
  866.             if (startIndex < 0 || startIndex > source.Length)
  867.                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  868.            
  869.             if (count < 0 || startIndex > source.Length - count)
  870.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
  871.            
  872.             if (options == CompareOptions.OrdinalIgnoreCase) {
  873.                 return TextInfo.nativeIndexOfCharOrdinalIgnoreCase(TextInfo.InvariantNativeTextInfo, source, value, startIndex, count);
  874.             }
  875.            
  876.             // Validate CompareOptions
  877.             // Ordinal can't be selected with other flags
  878.             if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal))
  879.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  880.            
  881.            
  882.             return IndexOfChar(m_pSortingTable, this.m_sortingLCID, source, value, startIndex, count, (int)options);
  883.         }
  884.        
  885.        
  886.         unsafe public virtual int IndexOf(string source, string value, int startIndex, int count, CompareOptions options)
  887.         {
  888.             // Validate inputs
  889.             if (source == null)
  890.                 throw new ArgumentNullException("source");
  891.             if (value == null)
  892.                 throw new ArgumentNullException("value");
  893.            
  894.             if (startIndex > source.Length) {
  895.                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  896.             }
  897.            
  898.             if (source.Length == 0) {
  899.                 if (value.Length == 0) {
  900.                     return 0;
  901.                 }
  902.                 return -1;
  903.             }
  904.            
  905.             if (startIndex < 0) {
  906.                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  907.             }
  908.            
  909.             if (count < 0 || startIndex > source.Length - count)
  910.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
  911.            
  912.             if (options == CompareOptions.OrdinalIgnoreCase) {
  913.                 return TextInfo.IndexOfStringOrdinalIgnoreCase(source, value, startIndex, count);
  914.             }
  915.            
  916.             // Validate CompareOptions
  917.             // Ordinal can't be selected with other flags
  918.             if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal))
  919.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  920.            
  921.            
  922.             return IndexOfString(m_pSortingTable, this.m_sortingLCID, source, value, startIndex, count, (int)options);
  923.         }
  924.        
  925.         // This native method will check the parameters and validate them accordingly.
  926.         // Native method: COMNlsInfo::IndexOfChar
  927.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  928.         unsafe private static extern int IndexOfChar(void* pSortingTable, int sortingLCID, string source, char value, int startIndex, int count, int options);
  929.        
  930.         // This native method will check the parameters and validate them accordingly.
  931.         // Native method: COMNlsInfo::IndexOfString
  932.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  933.         unsafe private static extern int IndexOfString(void* pSortingTable, int sortingLCID, string source, string value, int startIndex, int count, int options);
  934.        
  935.        
  936.         ////////////////////////////////////////////////////////////////////////
  937.         //
  938.         // LastIndexOf
  939.         //
  940.         // Returns the last index where value is found in string. The
  941.         // search starts from startIndex and ends at endIndex. Returns -1 if
  942.         // the specified value is not found. If value equals String.Empty,
  943.         // endIndex is returned. Throws IndexOutOfRange if startIndex or
  944.         // endIndex is less than zero or greater than the length of string.
  945.         // Throws ArgumentException if value is null.
  946.         //
  947.         ////////////////////////////////////////////////////////////////////////
  948.        
  949.        
  950.         unsafe public virtual int LastIndexOf(string source, char value)
  951.         {
  952.             if (source == null)
  953.                 throw new ArgumentNullException("source");
  954.            
  955.             // Can't start at negative index, so make sure we check for the length == 0 case.
  956.             return LastIndexOf(source, value, source.Length - 1, source.Length, CompareOptions.None);
  957.         }
  958.        
  959.        
  960.         unsafe public virtual int LastIndexOf(string source, string value)
  961.         {
  962.             if (source == null)
  963.                 throw new ArgumentNullException("source");
  964.            
  965.             // Can't start at negative index, so make sure we check for the length == 0 case.
  966.             return LastIndexOf(source, value, source.Length - 1, source.Length, CompareOptions.None);
  967.         }
  968.        
  969.        
  970.         unsafe public virtual int LastIndexOf(string source, char value, CompareOptions options)
  971.         {
  972.             if (source == null)
  973.                 throw new ArgumentNullException("source");
  974.            
  975.             // Can't start at negative index, so make sure we check for the length == 0 case.
  976.             return LastIndexOf(source, value, source.Length - 1, source.Length, options);
  977.         }
  978.        
  979.         unsafe public virtual int LastIndexOf(string source, string value, CompareOptions options)
  980.         {
  981.             if (source == null)
  982.                 throw new ArgumentNullException("source");
  983.            
  984.             // Can't start at negative index, so make sure we check for the length == 0 case.
  985.             return LastIndexOf(source, value, source.Length - 1, source.Length, options);
  986.         }
  987.        
  988.        
  989.         unsafe public virtual int LastIndexOf(string source, char value, int startIndex)
  990.         {
  991.             return LastIndexOf(source, value, startIndex, startIndex + 1, CompareOptions.None);
  992.         }
  993.        
  994.        
  995.         unsafe public virtual int LastIndexOf(string source, string value, int startIndex)
  996.         {
  997.             return LastIndexOf(source, value, startIndex, startIndex + 1, CompareOptions.None);
  998.         }
  999.        
  1000.        
  1001.         unsafe public virtual int LastIndexOf(string source, char value, int startIndex, CompareOptions options)
  1002.         {
  1003.             return LastIndexOf(source, value, startIndex, startIndex + 1, options);
  1004.         }
  1005.        
  1006.        
  1007.         unsafe public virtual int LastIndexOf(string source, string value, int startIndex, CompareOptions options)
  1008.         {
  1009.             return LastIndexOf(source, value, startIndex, startIndex + 1, options);
  1010.         }
  1011.        
  1012.        
  1013.         unsafe public virtual int LastIndexOf(string source, char value, int startIndex, int count)
  1014.         {
  1015.             return LastIndexOf(source, value, startIndex, count, CompareOptions.None);
  1016.         }
  1017.        
  1018.        
  1019.         unsafe public virtual int LastIndexOf(string source, string value, int startIndex, int count)
  1020.         {
  1021.             return LastIndexOf(source, value, startIndex, count, CompareOptions.None);
  1022.         }
  1023.        
  1024.        
  1025.         unsafe public virtual int LastIndexOf(string source, char value, int startIndex, int count, CompareOptions options)
  1026.         {
  1027.             // Verify Arguments
  1028.             if (source == null)
  1029.                 throw new ArgumentNullException("source");
  1030.            
  1031.             // Validate CompareOptions
  1032.             // Ordinal can't be selected with other flags
  1033.             if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal) && (options != CompareOptions.OrdinalIgnoreCase))
  1034.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  1035.            
  1036.             // Special case for 0 length input strings
  1037.             if (source.Length == 0 && (startIndex == -1 || startIndex == 0))
  1038.                 return -1;
  1039.            
  1040.             // Make sure we're not out of range
  1041.             if (startIndex < 0 || startIndex > source.Length)
  1042.                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  1043.            
  1044.             // Make sure that we allow startIndex == source.Length
  1045.             if (startIndex == source.Length) {
  1046.                 startIndex--;
  1047.                 if (count > 0)
  1048.                     count--;
  1049.             }
  1050.            
  1051.             // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
  1052.             if (count < 0 || startIndex - count + 1 < 0)
  1053.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
  1054.            
  1055.             if (options == CompareOptions.OrdinalIgnoreCase) {
  1056.                 return TextInfo.nativeLastIndexOfCharOrdinalIgnoreCase(TextInfo.InvariantNativeTextInfo, source, value, startIndex, count);
  1057.             }
  1058.            
  1059.            
  1060.             return (LastIndexOfChar(m_pSortingTable, this.m_sortingLCID, source, value, startIndex, count, (int)options));
  1061.         }
  1062.        
  1063.        
  1064.         unsafe public virtual int LastIndexOf(string source, string value, int startIndex, int count, CompareOptions options)
  1065.         {
  1066.             // Verify Arguments
  1067.             if (source == null)
  1068.                 throw new ArgumentNullException("source");
  1069.             if (value == null)
  1070.                 throw new ArgumentNullException("value");
  1071.            
  1072.             // Validate CompareOptions
  1073.             // Ordinal can't be selected with other flags
  1074.             if ((options & ValidIndexMaskOffFlags) != 0 && (options != CompareOptions.Ordinal) && (options != CompareOptions.OrdinalIgnoreCase))
  1075.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  1076.            
  1077.             // Special case for 0 length input strings
  1078.             if (source.Length == 0 && (startIndex == -1 || startIndex == 0))
  1079.                 return (value.Length == 0) ? 0 : -1;
  1080.            
  1081.             // Make sure we're not out of range
  1082.             if (startIndex < 0 || startIndex > source.Length)
  1083.                 throw new ArgumentOutOfRangeException("startIndex", Environment.GetResourceString("ArgumentOutOfRange_Index"));
  1084.            
  1085.             // Make sure that we allow startIndex == source.Length
  1086.             if (startIndex == source.Length) {
  1087.                 startIndex--;
  1088.                 if (count > 0)
  1089.                     count--;
  1090.                
  1091.                 // If we are looking for nothing, just return 0
  1092.                 if (value.Length == 0 && count >= 0 && startIndex - count + 1 >= 0)
  1093.                     return startIndex;
  1094.             }
  1095.            
  1096.             // 2nd have of this also catches when startIndex == MAXINT, so MAXINT - 0 + 1 == -1, which is < 0.
  1097.             if (count < 0 || startIndex - count + 1 < 0)
  1098.                 throw new ArgumentOutOfRangeException("count", Environment.GetResourceString("ArgumentOutOfRange_Count"));
  1099.            
  1100.             if (options == CompareOptions.OrdinalIgnoreCase) {
  1101.                 return TextInfo.LastIndexOfStringOrdinalIgnoreCase(source, value, startIndex, count);
  1102.             }
  1103.            
  1104.            
  1105.             return (LastIndexOfString(m_pSortingTable, this.m_sortingLCID, source, value, startIndex, count, (int)options));
  1106.         }
  1107.        
  1108.         // This native method will check the parameters and validate them accordingly.
  1109.         // Native method: COMNlsInfo::LastIndexOfChar
  1110.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1111.         unsafe static internal extern int LastIndexOfChar(void* pSortingTable, int sortingLCID, string source, char value, int startIndex, int count, int options);
  1112.        
  1113.         // This native method will check the parameters and validate them accordingly.
  1114.         // Native method: COMNlsInfo::LastIndexOfString
  1115.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  1116.         unsafe static internal extern int LastIndexOfString(void* pSortingTable, int sortingLCID, string source, string value, int startIndex, int count, int options);
  1117.        
  1118.        
  1119.         ////////////////////////////////////////////////////////////////////////
  1120.         //
  1121.         // GetSortKey
  1122.         //
  1123.         // Gets the SortKey for the given string with the given options.
  1124.         //
  1125.         ////////////////////////////////////////////////////////////////////////
  1126.        
  1127.        
  1128.         unsafe public virtual SortKey GetSortKey(string source, CompareOptions options)
  1129.         {
  1130.            
  1131.             // SortKey() will check the parameters and validate them accordingly.
  1132.            
  1133.             return (new SortKey(m_pSortingTable, this.m_sortingLCID, source, options));
  1134.         }
  1135.        
  1136.        
  1137.         unsafe public virtual SortKey GetSortKey(string source)
  1138.         {
  1139.            
  1140.            
  1141.            
  1142.             return (new SortKey(m_pSortingTable, this.m_sortingLCID, source, CompareOptions.None));
  1143.         }
  1144.        
  1145.         ////////////////////////////////////////////////////////////////////////
  1146.         //
  1147.         // Equals
  1148.         //
  1149.         // Implements Object.Equals(). Returns a boolean indicating whether
  1150.         // or not object refers to the same CompareInfo as the current
  1151.         // instance.
  1152.         //
  1153.         ////////////////////////////////////////////////////////////////////////
  1154.        
  1155.        
  1156.         public override bool Equals(object value)
  1157.         {
  1158.             CompareInfo that = value as CompareInfo;
  1159.            
  1160.             if (that != null) {
  1161.                 return this.m_sortingLCID == that.m_sortingLCID && this.Name.Equals(that.Name);
  1162.             }
  1163.            
  1164.             return (false);
  1165.         }
  1166.        
  1167.        
  1168.         ////////////////////////////////////////////////////////////////////////
  1169.         //
  1170.         // GetHashCode
  1171.         //
  1172.         // Implements Object.GetHashCode(). Returns the hash code for the
  1173.         // CompareInfo. The hash code is guaranteed to be the same for
  1174.         // CompareInfo A and B where A.Equals(B) is true.
  1175.         //
  1176.         ////////////////////////////////////////////////////////////////////////
  1177.        
  1178.        
  1179.         public override int GetHashCode()
  1180.         {
  1181.             return (this.Name.GetHashCode());
  1182.         }
  1183.        
  1184.         ////////////////////////////////////////////////////////////////////////
  1185.         //
  1186.         // GetHashCodeOfString
  1187.         //
  1188.         // This internal method allows a method that allows the equivalent of creating a Sortkey for a
  1189.         // string from CompareInfo, and generate a hashcode value from it. It is not very convenient
  1190.         // to use this method as is and it creates an unnecessary Sortkey object that will be GC'ed.
  1191.         //
  1192.         // The hash code is guaranteed to be the same for string A and B where A.Equals(B) is true and both
  1193.         // the CompareInfo and the CompareOptions are the same. If two different CompareInfo objects
  1194.         // treat the string the same way, this implementation will treat them differently (the same way that
  1195.         // Sortkey does at the moment).
  1196.         //
  1197.         // This method will never be made public itself, but public consumers of it could be created, e.g.:
  1198.         //
  1199.         // string.GetHashCode(CultureInfo)
  1200.         // string.GetHashCode(CompareInfo)
  1201.         // string.GetHashCode(CultureInfo, CompareOptions)
  1202.         // string.GetHashCode(CompareInfo, CompareOptions)
  1203.         // etc.
  1204.         //
  1205.         // (the methods above that take a CultureInfo would use CultureInfo.CompareInfo)
  1206.         //
  1207.         ////////////////////////////////////////////////////////////////////////
  1208.         unsafe internal int GetHashCodeOfString(string source, CompareOptions options)
  1209.         {
  1210.             //
  1211.             // Parameter validation
  1212.             //
  1213.             if (null == source) {
  1214.                 throw new ArgumentNullException("source");
  1215.             }
  1216.            
  1217.             if ((options & ValidHashCodeOfStringMaskOffFlags) != 0) {
  1218.                 throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFlag"), "options");
  1219.             }
  1220.            
  1221.             if (0 == source.Length) {
  1222.                 return (0);
  1223.             }
  1224.            
  1225.             //
  1226.             ////////////////////////////////////////////////////////////////////////
  1227.            
  1228.            
  1229.             return (nativeGetGlobalizedHashCode(m_pSortingTable, source, (int)options, this.m_sortingLCID));
  1230.         }
  1231.        
  1232.         ////////////////////////////////////////////////////////////////////////
  1233.         //
  1234.         // ToString
  1235.         //
  1236.         // Implements Object.ToString(). Returns a string describing the
  1237.         // CompareInfo.
  1238.         //
  1239.         ////////////////////////////////////////////////////////////////////////
  1240.        
  1241.        
  1242.         public override string ToString()
  1243.         {
  1244.             return ("CompareInfo - " + this.culture);
  1245.         }
  1246.        
  1247.        
  1248.         public int LCID {
  1249.             get { return (this.culture); }
  1250.         }
  1251.        
  1252.         // This is a thin wrapper for InitializeNativeCompareInfo() to provide the necessary
  1253.         // synchronization.
  1254.        
  1255. /*=================================InitializeCompareInfo==========================
  1256.         **Action: Makes a native C++ SortingTable pointer using the specified assembly and Win32 LCID.
  1257.         **Returns: a 32-bit pointer value to native C++ SrotingTable instance.
  1258.         **
  1259.         ** This method shouldn't be called when having synthetic culture (ELK)
  1260.         ** Couldn't assert her because this is a static method and cannot detect the synthetic cultures case.
  1261.         **
  1262.         **Arguments:
  1263.         **      pNativeGlobalizationAssembly    the 32-bit pointer value to a native C++ NLSAssembly instance.
  1264.         **      sortingLCID      the Win32 LCID.
  1265.         **Exceptions:
  1266.         **      None.
  1267.         ============================================================================*/       
  1268.        
  1269.         unsafe private static void* InitializeCompareInfo(void* pNativeGlobalizationAssembly, int sortingLCID)
  1270.         {
  1271.         }
  1272.        
  1273.         void* pTemp = null;
  1274.        
  1275.         bool tookLock = false;
  1276.     }
  1277. }

Developer Fusion