CompareInfo.cs 22 KB

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