* CultureInfo.cs: DateTimeFormat and NumberFormat can not be
[mono.git] / mcs / class / corlib / System.Globalization / CompareInfo.cs
1 //
2 // System.Globalization.CompareInfo
3 //
4 // Authors:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Dick Porter (dick@ximian.com)
7 //
8 // (C) Ximian, Inc. 2002
9 //
10
11 using System.Reflection;
12 using System.Runtime.Serialization;
13 using System.Runtime.CompilerServices;
14
15 namespace System.Globalization
16 {
17         [Serializable]
18         public class CompareInfo : IDeserializationCallback
19         {
20                 // Keep in synch with MonoCompareInfo in the runtime. 
21                 private int culture;
22                 [NonSerialized]
23                 private string icu_name;
24                 [NonSerialized]
25                 private IntPtr ICU_collator;
26                 private int win32LCID;  // Unused, but MS.NET serializes this
27                 
28                 /* Hide the .ctor() */
29                 CompareInfo() {}
30                 
31                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
32                 private extern void construct_compareinfo (string locale);
33                 
34                 internal CompareInfo (CultureInfo ci)
35                 {
36                         this.culture = ci.LCID;
37                         this.icu_name = ci.IcuName;
38                         this.construct_compareinfo (icu_name);
39                 }
40                 
41                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
42                 private extern void free_internal_collator ();
43                 
44                 ~CompareInfo ()
45                 {
46                         free_internal_collator ();
47                 }
48                 
49                 
50                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
51                 private extern int internal_compare (string str1, int offset1,
52                                                      int length1, string str2,
53                                                      int offset2, int length2,
54                                                      CompareOptions options);
55
56                 public virtual int Compare (string string1, string string2)
57                 {
58                         /* Short cuts... */
59                         if(string1.Length == 0) {
60                                 if(string2.Length == 0) {
61                                         return(0);
62                                 } else {
63                                         return(-1);
64                                 }
65                         } else if(string2.Length == 0) {
66                                 return(1);
67                         }
68
69                         return(internal_compare (string1, 0, string1.Length,
70                                                  string2, 0, string2.Length,
71                                                  CompareOptions.None));
72                 }
73
74                 public virtual int Compare (string string1, string string2,
75                                             CompareOptions options)
76                 {
77                         /* Short cuts... */
78                         if(string1.Length == 0) {
79                                 if(string2.Length == 0) {
80                                         return(0);
81                                 } else {
82                                         return(-1);
83                                 }
84                         } else if(string2.Length == 0) {
85                                 return(1);
86                         }
87
88                         return(internal_compare (string1, 0, string1.Length,
89                                                  string2, 0, string2.Length,
90                                                  options));
91                 }
92
93                 public virtual int Compare (string string1, int offset1,
94                                             string string2, int offset2)
95                 {
96                         /* Not in the spec, but ms does these short
97                          * cuts before checking the offsets (breaking
98                          * the offset >= string length specified check
99                          * in the process...)
100                          */
101                         if(string1.Length == 0 ||
102                            offset1 == string1.Length) {
103                                 if(string2.Length == 0 ||
104                                    offset2 == string2.Length) {
105                                         return(0);
106                                 } else {
107                                         return(-1);
108                                 }
109                         } else if(string2.Length == 0 ||
110                                   offset2 == string2.Length) {
111                                 return(1);
112                         }
113
114                         if(offset1 < 0 || offset2 < 0) {
115                                 throw new ArgumentOutOfRangeException ("Offsets must not be less than zero");
116                         }
117                         
118                         if(offset1 > string1.Length) {
119                                 throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
120                         }
121                         
122                         if(offset2 > string2.Length) {
123                                 throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
124                         }
125                         
126                         return(internal_compare (string1, offset1,
127                                                  string1.Length-offset1,
128                                                  string2, offset2,
129                                                  string2.Length-offset2,
130                                                  CompareOptions.None));
131                 }
132
133                 public virtual int Compare (string string1, int offset1,
134                                             string string2, int offset2,
135                                             CompareOptions options)
136                 {
137                         /* Not in the spec, but ms does these short
138                          * cuts before checking the offsets (breaking
139                          * the offset >= string length specified check
140                          * in the process...)
141                          */
142                         if(string1.Length == 0 ||
143                            offset1 == string1.Length) {
144                                 if(string2.Length == 0 ||
145                                    offset2 == string2.Length) {
146                                         return(0);
147                                 } else {
148                                         return(-1);
149                                 }
150                         } else if(string2.Length == 0 ||
151                                   offset2 == string2.Length) {
152                                 return(1);
153                         }
154
155                         if(offset1 < 0 || offset2 < 0) {
156                                 throw new ArgumentOutOfRangeException ("Offsets must not be less than zero");
157                         }
158                         
159                         if(offset1 > string1.Length) {
160                                 throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
161                         }
162                         
163                         if(offset2 > string2.Length) {
164                                 throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
165                         }
166                         
167                         return(internal_compare (string1, offset1,
168                                                  string1.Length-offset1,
169                                                  string2, offset2,
170                                                  string2.Length-offset1,
171                                                  options));
172                 }
173
174                 public virtual int Compare (string string1, int offset1,
175                                             int length1, string string2,
176                                             int offset2, int length2)
177                 {
178                         /* Not in the spec, but ms does these short
179                          * cuts before checking the offsets (breaking
180                          * the offset >= string length specified check
181                          * in the process...)
182                          */
183                         if(string1.Length == 0 ||
184                            offset1 == string1.Length ||
185                            length1 == 0) {
186                                 if(string2.Length == 0 ||
187                                    offset2 == string2.Length ||
188                                    length2 == 0) {
189                                         return(0);
190                                 } else {
191                                         return(-1);
192                                 }
193                         } else if(string2.Length == 0 ||
194                                   offset2 == string2.Length ||
195                                   length2 == 0) {
196                                 return(1);
197                         }
198
199                         if(offset1 < 0 || length1 < 0 ||
200                            offset2 < 0 || length2 < 0) {
201                                 throw new ArgumentOutOfRangeException ("Offsets and lengths must not be less than zero");
202                         }
203                         
204                         if(offset1 > string1.Length) {
205                                 throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
206                         }
207                         
208                         if(offset2 > string2.Length) {
209                                 throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
210                         }
211                         
212                         if(length1 > string1.Length-offset1) {
213                                 throw new ArgumentOutOfRangeException ("Length1 is greater than the number of characters from offset1 to the end of string1");
214                         }
215                         
216                         if(length2 > string2.Length-offset2) {
217                                 throw new ArgumentOutOfRangeException ("Length2 is greater than the number of characters from offset2 to the end of string2");
218                         }
219                         
220                         return(internal_compare (string1, offset1, length1,
221                                                  string2, offset2, length2,
222                                                  CompareOptions.None));
223                 }
224
225                 public virtual int Compare (string string1, int offset1,
226                                             int length1, string string2,
227                                             int offset2, int length2,
228                                             CompareOptions options)
229                 {
230                         /* Not in the spec, but ms does these short
231                          * cuts before checking the offsets (breaking
232                          * the offset >= string length specified check
233                          * in the process...)
234                          */
235                         if(string1.Length == 0 ||
236                            offset1 == string1.Length ||
237                            length1 == 0) {
238                                 if(string2.Length == 0 ||
239                                    offset2 == string2.Length ||
240                                    length2 == 0) {
241                                         return(0);
242                                 } else {
243                                         return(-1);
244                                 }
245                         } else if(string2.Length == 0 ||
246                                   offset2 == string2.Length ||
247                                   length2 == 0) {
248                                 return(1);
249                         }
250
251                         if(offset1 < 0 || length1 < 0 ||
252                            offset2 < 0 || length2 < 0) {
253                                 throw new ArgumentOutOfRangeException ("Offsets and lengths must not be less than zero");
254                         }
255                         
256                         if(offset1 > string1.Length) {
257                                 throw new ArgumentOutOfRangeException ("Offset1 is greater than or equal to the length of string1");
258                         }
259                         
260                         if(offset2 > string2.Length) {
261                                 throw new ArgumentOutOfRangeException ("Offset2 is greater than or equal to the length of string2");
262                         }
263                         
264                         if(length1 > string1.Length-offset1) {
265                                 throw new ArgumentOutOfRangeException ("Length1 is greater than the number of characters from offset1 to the end of string1");
266                         }
267                         
268                         if(length2 > string2.Length-offset2) {
269                                 throw new ArgumentOutOfRangeException ("Length2 is greater than the number of characters from offset2 to the end of string2");
270                         }
271                         
272                         return(internal_compare (string1, offset1, length1,
273                                                  string2, offset2, length2,
274                                                  options));
275                 }
276
277                 public override bool Equals(object value)
278                 {
279                         CompareInfo other=value as CompareInfo;
280                         if(other==null) {
281                                 return(false);
282                         }
283                         
284                         return(other.culture==culture);
285                 }
286
287                 public static CompareInfo GetCompareInfo(int culture)
288                 {
289                         return(new CultureInfo (culture).CompareInfo);
290                 }
291
292                 public static CompareInfo GetCompareInfo(string name)
293                 {
294                         if(name == null) {
295                                 throw new ArgumentNullException("name");
296                         }
297                         return(new CultureInfo (name).CompareInfo);
298                 }
299
300                 public static CompareInfo GetCompareInfo(int culture,
301                                                          Assembly assembly)
302                 {
303                         /* The assembly parameter is supposedly there
304                          * to allow some sort of compare algorithm
305                          * versioning.
306                          */
307                         if(assembly == null) {
308                                 throw new ArgumentNullException("assembly");
309                         }
310                         if(assembly!=typeof (Object).Module.Assembly) {
311                                 throw new ArgumentException ("Assembly is an invalid type");
312                         }
313                         return(GetCompareInfo (culture));
314                 }
315
316                 public static CompareInfo GetCompareInfo(string name,
317                                                          Assembly assembly)
318                 {
319                         /* The assembly parameter is supposedly there
320                          * to allow some sort of compare algorithm
321                          * versioning.
322                          */
323                         if(name == null) {
324                                 throw new ArgumentNullException("name");
325                         }
326                         if(assembly == null) {
327                                 throw new ArgumentNullException("assembly");
328                         }
329                         if(assembly!=typeof (Object).Module.Assembly) {
330                                 throw new ArgumentException ("Assembly is an invalid type");
331                         }
332                         return(GetCompareInfo (name));
333                 }
334
335                 public override int GetHashCode()
336                 {
337                         return(LCID);
338                 }
339
340                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
341                 private extern void assign_sortkey (object key, string source,
342                                                     CompareOptions options);
343                 
344                 public virtual SortKey GetSortKey(string source)
345                 {
346                         return(GetSortKey (source, CompareOptions.None));
347                 }
348
349                 public virtual SortKey GetSortKey(string source,
350                                                   CompareOptions options)
351                 {
352                         SortKey key=new SortKey (culture, source, options);
353
354                         /* Need to do the icall here instead of in the
355                          * SortKey constructor, as we need access to
356                          * this instance's collator.
357                          */
358                         assign_sortkey (key, source, options);
359                         
360                         return(key);
361                 }
362
363                 public virtual int IndexOf (string source, char value)
364                 {
365                         return(IndexOf (source, value, 0, source.Length,
366                                         CompareOptions.None));
367                 }
368
369                 public virtual int IndexOf (string source, string value)
370                 {
371                         return(IndexOf (source, value, 0, source.Length,
372                                         CompareOptions.None));
373                 }
374
375                 public virtual int IndexOf (string source, char value,
376                                             CompareOptions options)
377                 {
378                         return(IndexOf (source, value, 0, source.Length,
379                                         options));
380                 }
381
382                 public virtual int IndexOf (string source, char value,
383                                             int startIndex)
384                 {
385                         return(IndexOf (source, value, startIndex,
386                                         source.Length - startIndex,
387                                         CompareOptions.None));
388                 }
389                 
390                 public virtual int IndexOf (string source, string value,
391                                             CompareOptions options)
392                 {
393                         return(IndexOf (source, value, 0, source.Length,
394                                         options));
395                 }
396
397                 public virtual int IndexOf (string source, string value,
398                                             int startIndex)
399                 {
400                         return(IndexOf (source, value, startIndex,
401                                         source.Length - startIndex,
402                                         CompareOptions.None));
403                 }
404
405                 public virtual int IndexOf (string source, char value,
406                                             int startIndex,
407                                             CompareOptions options)
408                 {
409                         return(IndexOf (source, value, startIndex,
410                                         source.Length - startIndex, options));
411                 }
412
413                 public virtual int IndexOf (string source, char value,
414                                             int startIndex, int count)
415                 {
416                         return IndexOf (source, value, startIndex, count,
417                                         CompareOptions.None);
418                 }
419
420                 public virtual int IndexOf (string source, string value,
421                                             int startIndex,
422                                             CompareOptions options)
423                 {
424                         return(IndexOf (source, value, startIndex,
425                                         source.Length - startIndex, options));
426                 }
427
428                 public virtual int IndexOf (string source, string value,
429                                             int startIndex, int count)
430                 {
431                         return(IndexOf (source, value, startIndex, count,
432                                         CompareOptions.None));
433                 }
434
435                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
436                 private extern int internal_index (string source, int sindex,
437                                                    int count, char value,
438                                                    CompareOptions options,
439                                                    bool first);
440                 
441                 public virtual int IndexOf (string source, char value,
442                                             int startIndex, int count,
443                                             CompareOptions options)
444                 {
445                         if(source==null) {
446                                 throw new ArgumentNullException ("source");
447                         }
448                         if(startIndex<0) {
449                                 throw new ArgumentOutOfRangeException ("startIndex");
450                         }
451                         if(count<0 || (source.Length - startIndex) < count) {
452                                 throw new ArgumentOutOfRangeException ("count");
453                         }
454                         if((options & CompareOptions.StringSort)!=0) {
455                                 throw new ArgumentException ("StringSort is not a valid CompareOption for this method");
456                         }
457                         
458                         if(count==0) {
459                                 return(-1);
460                         }
461
462                         if((options & CompareOptions.Ordinal)!=0) {
463                                 for(int pos=startIndex;
464                                     pos < startIndex + count;
465                                     pos++) {
466                                         if(source[pos]==value) {
467                                                 return(pos);
468                                         }
469                                 }
470                                 return(-1);
471                         } else {
472                                 return (internal_index (source, startIndex,
473                                                         count, value, options,
474                                                         true));
475                         }
476                 }
477
478                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
479                 private extern int internal_index (string source, int sindex,
480                                                    int count, string value,
481                                                    CompareOptions options,
482                                                    bool first);
483                 
484                 public virtual int IndexOf (string source, string value,
485                                             int startIndex, int count,
486                                             CompareOptions options)
487                 {
488                         if(source==null) {
489                                 throw new ArgumentNullException ("source");
490                         }
491                         if(value==null) {
492                                 throw new ArgumentNullException ("value");
493                         }
494                         if(startIndex<0) {
495                                 throw new ArgumentOutOfRangeException ("startIndex");
496                         }
497                         if(count<0 || (source.Length - startIndex) < count) {
498                                 throw new ArgumentOutOfRangeException ("count");
499                         }
500                         if(count==0) {
501                                 return(-1);
502                         }
503
504                         return (internal_index (source, startIndex, count,
505                                                 value, options, true));
506                 }
507
508                 public virtual bool IsPrefix(string source, string prefix)
509                 {
510                         return(IsPrefix (source, prefix, CompareOptions.None));
511                 }
512
513                 public virtual bool IsPrefix(string source, string prefix,
514                                              CompareOptions options)
515                 {
516                         if(source == null) {
517                                 throw new ArgumentNullException("source");
518                         }
519                         if(prefix == null) {
520                                 throw new ArgumentNullException("prefix");
521                         }
522
523                         if(source.Length < prefix.Length) {
524                                 return(false);
525                         } else {
526                                 return(Compare (source, 0, prefix.Length,
527                                                 prefix, 0, prefix.Length,
528                                                 options)==0);
529                         }
530                 }
531
532                 public virtual bool IsSuffix(string source, string suffix)
533                 {
534                         return(IsSuffix (source, suffix, CompareOptions.None));
535                 }
536
537                 public virtual bool IsSuffix(string source, string suffix,
538                                              CompareOptions options)
539                 {
540                         if(source == null) {
541                                 throw new ArgumentNullException("source");
542                         }
543                         if(suffix == null) {
544                                 throw new ArgumentNullException("suffix");
545                         }
546
547                         if(source.Length < suffix.Length) {
548                                 return(false);
549                         } else {
550                                 return(Compare (source,
551                                                 source.Length - suffix.Length,
552                                                 suffix.Length, suffix, 0,
553                                                 suffix.Length, options)==0);
554                         }
555                 }
556
557                 public virtual int LastIndexOf(string source, char value)
558                 {
559                         return(LastIndexOf (source, value, 0, source.Length,
560                                             CompareOptions.None));
561                 }
562
563                 public virtual int LastIndexOf(string source, string value)
564                 {
565                         return(LastIndexOf (source, value, 0, source.Length,
566                                             CompareOptions.None));
567                 }
568
569                 public virtual int LastIndexOf(string source, char value,
570                                                CompareOptions options)
571                 {
572                         return(LastIndexOf (source, value, 0, source.Length,
573                                             options));
574                 }
575
576                 public virtual int LastIndexOf(string source, char value,
577                                                int startIndex)
578                 {
579                         return(LastIndexOf (source, value, startIndex,
580                                             source.Length - startIndex,
581                                             CompareOptions.None));
582                 }
583
584                 public virtual int LastIndexOf(string source, string value,
585                                                CompareOptions options)
586                 {
587                         return(LastIndexOf (source, value, 0, source.Length,
588                                             options));
589                 }
590
591                 public virtual int LastIndexOf(string source, string value,
592                                                int startIndex)
593                 {
594                         return(LastIndexOf (source, value, startIndex,
595                                             source.Length - startIndex,
596                                             CompareOptions.None));
597                 }
598
599                 public virtual int LastIndexOf(string source, char value,
600                                                int startIndex,
601                                                CompareOptions options)
602                 {
603                         return(LastIndexOf (source, value, startIndex,
604                                             source.Length - startIndex,
605                                             options));
606                 }
607
608                 public virtual int LastIndexOf(string source, char value,
609                                                int startIndex, int count)
610                 {
611                         return(LastIndexOf (source, value, startIndex, count,
612                                             CompareOptions.None));
613                 }
614
615                 public virtual int LastIndexOf(string source, string value,
616                                                int startIndex,
617                                                CompareOptions options)
618                 {
619                         return(LastIndexOf (source, value, startIndex,
620                                             source.Length - startIndex,
621                                             options));
622                 }
623
624                 public virtual int LastIndexOf(string source, string value,
625                                                int startIndex, int count)
626                 {
627                         return(LastIndexOf (source, value, startIndex, count,
628                                             CompareOptions.None));
629                 }
630
631                 public virtual int LastIndexOf(string source, char value,
632                                                int startIndex, int count,
633                                                CompareOptions options)
634                 {
635                         if(source == null) {
636                                 throw new ArgumentNullException("source");
637                         }
638                         if(startIndex < 0) {
639                                 throw new ArgumentOutOfRangeException ("startIndex");
640                         }
641                         if(count < 0 || (startIndex - count) < -1) {
642                                 throw new ArgumentOutOfRangeException("count");
643                         }
644                         if((options & CompareOptions.StringSort)!=0) {
645                                 throw new ArgumentException ("StringSort is not a valid CompareOption for this method");
646                         }
647                         
648                         if(count==0) {
649                                 return(-1);
650                         }
651
652                         if((options & CompareOptions.Ordinal)!=0) {
653                                 for(int pos=startIndex;
654                                     pos > startIndex - count;
655                                     pos--) {
656                                         if(source[pos]==value) {
657                                                 return(pos);
658                                         }
659                                 }
660                                 return(-1);
661                         } else {
662                                 return (internal_index (source, startIndex,
663                                                         count, value, options,
664                                                         false));
665                         }
666                 }
667
668                 public virtual int LastIndexOf(string source, string value,
669                                                int startIndex, int count,
670                                                CompareOptions options)
671                 {
672                         if(source == null) {
673                                 throw new ArgumentNullException("source");
674                         }
675                         if(value == null) {
676                                 throw new ArgumentNullException("value");
677                         }
678                         if(startIndex < 0) {
679                                 throw new ArgumentOutOfRangeException ("startIndex");
680                         }
681                         if(count < 0 || (startIndex - count) < -1) {
682                                 throw new ArgumentOutOfRangeException("count");
683                         }
684                         if(count == 0) {
685                                 return(-1);
686                         }
687
688                         int valuelen=value.Length;
689                         if(valuelen==0) {
690                                 return(0);
691                         }
692
693                         return(internal_index (source, startIndex, count,
694                                                value, options, false));
695                 }
696
697                 public override string ToString()
698                 {
699                         return("CompareInfo - "+culture);
700                 }
701
702                 void IDeserializationCallback.OnDeserialization(object sender)
703                 {
704                         /* This will build the ICU collator, and store
705                          * the pointer in ICU_collator
706                          */
707                         try {
708                                 this.construct_compareinfo (icu_name);
709                         } catch {
710                                 ICU_collator=IntPtr.Zero;
711                         }
712                 }
713
714                 /* LAMESPEC: not mentioned in the spec, but corcompare
715                  * shows it.  Some documentation about what it does
716                  * would be nice.
717                  */
718                 public int LCID
719                 {
720                         get {
721                                 return(culture);
722                         }
723                 }
724         }
725 }