2 // System.Globalization.CompareInfo
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Dick Porter (dick@ximian.com)
8 // (C) Ximian, Inc. 2002
12 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System.Reflection;
35 using System.Runtime.Serialization;
36 using System.Runtime.CompilerServices;
38 namespace System.Globalization
41 public class CompareInfo : IDeserializationCallback
43 // Keep in synch with MonoCompareInfo in the runtime.
46 private string icu_name;
48 private IntPtr ICU_collator;
49 private int win32LCID; // Unused, but MS.NET serializes this
51 /* Hide the .ctor() */
54 [MethodImplAttribute (MethodImplOptions.InternalCall)]
55 private extern void construct_compareinfo (string locale);
57 internal CompareInfo (CultureInfo ci)
59 this.culture = ci.LCID;
60 this.icu_name = ci.IcuName;
61 this.construct_compareinfo (icu_name);
64 [MethodImplAttribute (MethodImplOptions.InternalCall)]
65 private extern void free_internal_collator ();
69 free_internal_collator ();
73 [MethodImplAttribute (MethodImplOptions.InternalCall)]
74 private extern int internal_compare (string str1, int offset1,
75 int length1, string str2,
76 int offset2, int length2,
77 CompareOptions options);
79 public virtual int Compare (string string1, string string2)
82 if(string1.Length == 0) {
83 if(string2.Length == 0) {
88 } else if(string2.Length == 0) {
92 return(internal_compare (string1, 0, string1.Length,
93 string2, 0, string2.Length,
94 CompareOptions.None));
97 public virtual int Compare (string string1, string string2,
98 CompareOptions options)
101 if(string1.Length == 0) {
102 if(string2.Length == 0) {
107 } else if(string2.Length == 0) {
111 return(internal_compare (string1, 0, string1.Length,
112 string2, 0, string2.Length,
116 public virtual int Compare (string string1, int offset1,
117 string string2, int offset2)
119 /* Not in the spec, but ms does these short
120 * cuts before checking the offsets (breaking
121 * the offset >= string length specified check
124 if(string1.Length == 0 ||
125 offset1 == string1.Length) {
126 if(string2.Length == 0 ||
127 offset2 == string2.Length) {
132 } else if(string2.Length == 0 ||
133 offset2 == string2.Length) {
137 if(offset1 < 0 || offset2 < 0) {
138 throw new ArgumentOutOfRangeException ("Offsets must not be less than zero");
141 if(offset1 > string1.Length) {
142 throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
145 if(offset2 > string2.Length) {
146 throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
149 return(internal_compare (string1, offset1,
150 string1.Length-offset1,
152 string2.Length-offset2,
153 CompareOptions.None));
156 public virtual int Compare (string string1, int offset1,
157 string string2, int offset2,
158 CompareOptions options)
160 /* Not in the spec, but ms does these short
161 * cuts before checking the offsets (breaking
162 * the offset >= string length specified check
165 if(string1.Length == 0 ||
166 offset1 == string1.Length) {
167 if(string2.Length == 0 ||
168 offset2 == string2.Length) {
173 } else if(string2.Length == 0 ||
174 offset2 == string2.Length) {
178 if(offset1 < 0 || offset2 < 0) {
179 throw new ArgumentOutOfRangeException ("Offsets must not be less than zero");
182 if(offset1 > string1.Length) {
183 throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
186 if(offset2 > string2.Length) {
187 throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
190 return(internal_compare (string1, offset1,
191 string1.Length-offset1,
193 string2.Length-offset1,
197 public virtual int Compare (string string1, int offset1,
198 int length1, string string2,
199 int offset2, int length2)
201 /* Not in the spec, but ms does these short
202 * cuts before checking the offsets (breaking
203 * the offset >= string length specified check
206 if(string1.Length == 0 ||
207 offset1 == string1.Length ||
209 if(string2.Length == 0 ||
210 offset2 == string2.Length ||
216 } else if(string2.Length == 0 ||
217 offset2 == string2.Length ||
222 if(offset1 < 0 || length1 < 0 ||
223 offset2 < 0 || length2 < 0) {
224 throw new ArgumentOutOfRangeException ("Offsets and lengths must not be less than zero");
227 if(offset1 > string1.Length) {
228 throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
231 if(offset2 > string2.Length) {
232 throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
235 if(length1 > string1.Length-offset1) {
236 throw new ArgumentOutOfRangeException ("Length1 is greater than the number of characters from offset1 to the end of string1");
239 if(length2 > string2.Length-offset2) {
240 throw new ArgumentOutOfRangeException ("Length2 is greater than the number of characters from offset2 to the end of string2");
243 return(internal_compare (string1, offset1, length1,
244 string2, offset2, length2,
245 CompareOptions.None));
248 public virtual int Compare (string string1, int offset1,
249 int length1, string string2,
250 int offset2, int length2,
251 CompareOptions options)
253 /* Not in the spec, but ms does these short
254 * cuts before checking the offsets (breaking
255 * the offset >= string length specified check
258 if(string1.Length == 0 ||
259 offset1 == string1.Length ||
261 if(string2.Length == 0 ||
262 offset2 == string2.Length ||
268 } else if(string2.Length == 0 ||
269 offset2 == string2.Length ||
274 if(offset1 < 0 || length1 < 0 ||
275 offset2 < 0 || length2 < 0) {
276 throw new ArgumentOutOfRangeException ("Offsets and lengths must not be less than zero");
279 if(offset1 > string1.Length) {
280 throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
283 if(offset2 > string2.Length) {
284 throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
287 if(length1 > string1.Length-offset1) {
288 throw new ArgumentOutOfRangeException ("Length1 is greater than the number of characters from offset1 to the end of string1");
291 if(length2 > string2.Length-offset2) {
292 throw new ArgumentOutOfRangeException ("Length2 is greater than the number of characters from offset2 to the end of string2");
295 return(internal_compare (string1, offset1, length1,
296 string2, offset2, length2,
300 public override bool Equals(object value)
302 CompareInfo other=value as CompareInfo;
307 return(other.culture==culture);
310 public static CompareInfo GetCompareInfo(int culture)
312 return(new CultureInfo (culture).CompareInfo);
315 public static CompareInfo GetCompareInfo(string name)
318 throw new ArgumentNullException("name");
320 return(new CultureInfo (name).CompareInfo);
323 public static CompareInfo GetCompareInfo(int culture,
326 /* The assembly parameter is supposedly there
327 * to allow some sort of compare algorithm
330 if(assembly == null) {
331 throw new ArgumentNullException("assembly");
333 if(assembly!=typeof (Object).Module.Assembly) {
334 throw new ArgumentException ("Assembly is an invalid type");
336 return(GetCompareInfo (culture));
339 public static CompareInfo GetCompareInfo(string name,
342 /* The assembly parameter is supposedly there
343 * to allow some sort of compare algorithm
347 throw new ArgumentNullException("name");
349 if(assembly == null) {
350 throw new ArgumentNullException("assembly");
352 if(assembly!=typeof (Object).Module.Assembly) {
353 throw new ArgumentException ("Assembly is an invalid type");
355 return(GetCompareInfo (name));
358 public override int GetHashCode()
363 [MethodImplAttribute (MethodImplOptions.InternalCall)]
364 private extern void assign_sortkey (object key, string source,
365 CompareOptions options);
367 public virtual SortKey GetSortKey(string source)
369 return(GetSortKey (source, CompareOptions.None));
372 public virtual SortKey GetSortKey(string source,
373 CompareOptions options)
375 SortKey key=new SortKey (culture, source, options);
377 /* Need to do the icall here instead of in the
378 * SortKey constructor, as we need access to
379 * this instance's collator.
381 assign_sortkey (key, source, options);
386 public virtual int IndexOf (string source, char value)
388 return(IndexOf (source, value, 0, source.Length,
389 CompareOptions.None));
392 public virtual int IndexOf (string source, string value)
394 return(IndexOf (source, value, 0, source.Length,
395 CompareOptions.None));
398 public virtual int IndexOf (string source, char value,
399 CompareOptions options)
401 return(IndexOf (source, value, 0, source.Length,
405 public virtual int IndexOf (string source, char value,
408 return(IndexOf (source, value, startIndex,
409 source.Length - startIndex,
410 CompareOptions.None));
413 public virtual int IndexOf (string source, string value,
414 CompareOptions options)
416 return(IndexOf (source, value, 0, source.Length,
420 public virtual int IndexOf (string source, string value,
423 return(IndexOf (source, value, startIndex,
424 source.Length - startIndex,
425 CompareOptions.None));
428 public virtual int IndexOf (string source, char value,
430 CompareOptions options)
432 return(IndexOf (source, value, startIndex,
433 source.Length - startIndex, options));
436 public virtual int IndexOf (string source, char value,
437 int startIndex, int count)
439 return IndexOf (source, value, startIndex, count,
440 CompareOptions.None);
443 public virtual int IndexOf (string source, string value,
445 CompareOptions options)
447 return(IndexOf (source, value, startIndex,
448 source.Length - startIndex, options));
451 public virtual int IndexOf (string source, string value,
452 int startIndex, int count)
454 return(IndexOf (source, value, startIndex, count,
455 CompareOptions.None));
458 [MethodImplAttribute (MethodImplOptions.InternalCall)]
459 private extern int internal_index (string source, int sindex,
460 int count, char value,
461 CompareOptions options,
464 public virtual int IndexOf (string source, char value,
465 int startIndex, int count,
466 CompareOptions options)
469 throw new ArgumentNullException ("source");
472 throw new ArgumentOutOfRangeException ("startIndex");
474 if(count<0 || (source.Length - startIndex) < count) {
475 throw new ArgumentOutOfRangeException ("count");
477 if((options & CompareOptions.StringSort)!=0) {
478 throw new ArgumentException ("StringSort is not a valid CompareOption for this method");
485 if((options & CompareOptions.Ordinal)!=0) {
486 for(int pos=startIndex;
487 pos < startIndex + count;
489 if(source[pos]==value) {
495 return (internal_index (source, startIndex,
496 count, value, options,
501 [MethodImplAttribute (MethodImplOptions.InternalCall)]
502 private extern int internal_index (string source, int sindex,
503 int count, string value,
504 CompareOptions options,
507 public virtual int IndexOf (string source, string value,
508 int startIndex, int count,
509 CompareOptions options)
512 throw new ArgumentNullException ("source");
515 throw new ArgumentNullException ("value");
518 throw new ArgumentOutOfRangeException ("startIndex");
520 if(count<0 || (source.Length - startIndex) < count) {
521 throw new ArgumentOutOfRangeException ("count");
527 return (internal_index (source, startIndex, count,
528 value, options, true));
531 public virtual bool IsPrefix(string source, string prefix)
533 return(IsPrefix (source, prefix, CompareOptions.None));
536 public virtual bool IsPrefix(string source, string prefix,
537 CompareOptions options)
540 throw new ArgumentNullException("source");
543 throw new ArgumentNullException("prefix");
546 if(source.Length < prefix.Length) {
549 return(Compare (source, 0, prefix.Length,
550 prefix, 0, prefix.Length,
555 public virtual bool IsSuffix(string source, string suffix)
557 return(IsSuffix (source, suffix, CompareOptions.None));
560 public virtual bool IsSuffix(string source, string suffix,
561 CompareOptions options)
564 throw new ArgumentNullException("source");
567 throw new ArgumentNullException("suffix");
570 if(source.Length < suffix.Length) {
573 return(Compare (source,
574 source.Length - suffix.Length,
575 suffix.Length, suffix, 0,
576 suffix.Length, options)==0);
580 public virtual int LastIndexOf(string source, char value)
582 return(LastIndexOf (source, value, source.Length - 1,
583 source.Length, CompareOptions.None));
586 public virtual int LastIndexOf(string source, string value)
588 return(LastIndexOf (source, value, source.Length - 1,
589 source.Length, CompareOptions.None));
592 public virtual int LastIndexOf(string source, char value,
593 CompareOptions options)
595 return(LastIndexOf (source, value, source.Length - 1,
596 source.Length, options));
599 public virtual int LastIndexOf(string source, char value,
602 return(LastIndexOf (source, value, startIndex,
604 CompareOptions.None));
607 public virtual int LastIndexOf(string source, string value,
608 CompareOptions options)
610 return(LastIndexOf (source, value, source.Length - 1,
611 source.Length, options));
614 public virtual int LastIndexOf(string source, string value,
617 return(LastIndexOf (source, value, startIndex,
619 CompareOptions.None));
622 public virtual int LastIndexOf(string source, char value,
624 CompareOptions options)
626 return(LastIndexOf (source, value, startIndex,
631 public virtual int LastIndexOf(string source, char value,
632 int startIndex, int count)
634 return(LastIndexOf (source, value, startIndex, count,
635 CompareOptions.None));
638 public virtual int LastIndexOf(string source, string value,
640 CompareOptions options)
642 return(LastIndexOf (source, value, startIndex,
647 public virtual int LastIndexOf(string source, string value,
648 int startIndex, int count)
650 return(LastIndexOf (source, value, startIndex, count,
651 CompareOptions.None));
654 public virtual int LastIndexOf(string source, char value,
655 int startIndex, int count,
656 CompareOptions options)
659 throw new ArgumentNullException("source");
662 throw new ArgumentOutOfRangeException ("startIndex");
664 if(count < 0 || (startIndex - count) < -1) {
665 throw new ArgumentOutOfRangeException("count");
667 if((options & CompareOptions.StringSort)!=0) {
668 throw new ArgumentException ("StringSort is not a valid CompareOption for this method");
675 if((options & CompareOptions.Ordinal)!=0) {
676 for(int pos=startIndex;
677 pos > startIndex - count;
679 if(source[pos]==value) {
685 return (internal_index (source, startIndex,
686 count, value, options,
691 public virtual int LastIndexOf(string source, string value,
692 int startIndex, int count,
693 CompareOptions options)
696 throw new ArgumentNullException("source");
699 throw new ArgumentNullException("value");
702 throw new ArgumentOutOfRangeException ("startIndex");
704 if(count < 0 || (startIndex - count) < -1) {
705 throw new ArgumentOutOfRangeException("count");
711 int valuelen=value.Length;
716 return(internal_index (source, startIndex, count,
717 value, options, false));
720 public override string ToString()
722 return("CompareInfo - "+culture);
725 void IDeserializationCallback.OnDeserialization(object sender)
727 /* This will build the ICU collator, and store
728 * the pointer in ICU_collator
731 this.construct_compareinfo (icu_name);
733 ICU_collator=IntPtr.Zero;
737 /* LAMESPEC: not mentioned in the spec, but corcompare
738 * shows it. Some documentation about what it does