GenericParameter.cs: override Module properly
[mcs.git] / class / corlib / System.Globalization / TextInfo.cs
blobd77993bb90e9d74ecb986b0e0cc187ca885bd8f8
1 //
2 // System.Globalization.TextInfo.cs
3 //
4 // Authors:
5 // Dick Porter (dick@ximian.com)
6 // Duncan Mak (duncan@ximian.com)
7 // Atsushi Enomoto (atsushi@ximian.com)
8 // Sebastien Pouliot <sebastien@ximian.com>
9 //
10 // (C) 2002 Ximian, Inc.
11 // (C) 2005 Novell, Inc.
13 // TODO:
14 // Missing the various code page mappings.
15 // Missing the OnDeserialization implementation.
17 // Copyright (C) 2004, 2005 Novell, Inc (http://www.novell.com)
19 // Permission is hereby granted, free of charge, to any person obtaining
20 // a copy of this software and associated documentation files (the
21 // "Software"), to deal in the Software without restriction, including
22 // without limitation the rights to use, copy, modify, merge, publish,
23 // distribute, sublicense, and/or sell copies of the Software, and to
24 // permit persons to whom the Software is furnished to do so, subject to
25 // the following conditions:
26 //
27 // The above copyright notice and this permission notice shall be
28 // included in all copies or substantial portions of the Software.
29 //
30 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
34 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
35 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
36 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
39 using System.Runtime.Serialization;
40 using System.Runtime.InteropServices;
41 using System.Text;
43 namespace System.Globalization {
45 [Serializable]
46 [ComVisible (true)]
47 [MonoTODO ("IDeserializationCallback isn't implemented.")]
48 public class TextInfo: IDeserializationCallback, ICloneable
50 [StructLayout (LayoutKind.Sequential)]
51 struct Data {
52 public int ansi;
53 public int ebcdic;
54 public int mac;
55 public int oem;
56 public byte list_sep;
59 string m_listSeparator;
60 bool m_isReadOnly;
61 string customCultureName;
63 #pragma warning disable 169
64 [NonSerialized]
65 int m_nDataItem;
66 bool m_useUserOverride;
67 #pragma warning restore 169
69 int m_win32LangID;
71 [NonSerialized]
72 readonly CultureInfo ci;
74 [NonSerialized]
75 readonly bool handleDotI;
77 [NonSerialized]
78 readonly Data data;
80 internal unsafe TextInfo (CultureInfo ci, int lcid, void* data, bool read_only)
82 this.m_isReadOnly = read_only;
83 this.m_win32LangID = lcid;
84 this.ci = ci;
85 if (data != null)
86 this.data = *(Data*) data;
87 else {
88 this.data = new Data ();
89 this.data.list_sep = (byte) ',';
92 CultureInfo tmp = ci;
93 while (tmp.Parent != null && tmp.Parent.LCID != 0x7F && tmp.Parent != tmp)
94 tmp = tmp.Parent;
96 if (tmp != null) {
97 switch (tmp.LCID) {
98 case 44: // Azeri (az)
99 case 31: // Turkish (tr)
100 handleDotI = true;
101 break;
106 private TextInfo (TextInfo textInfo)
108 m_win32LangID = textInfo.m_win32LangID;
109 m_nDataItem = textInfo.m_nDataItem;
110 m_useUserOverride = textInfo.m_useUserOverride;
111 m_listSeparator = textInfo.ListSeparator;
112 customCultureName = textInfo.CultureName;
113 ci = textInfo.ci;
114 handleDotI = textInfo.handleDotI;
115 data = textInfo.data;
118 public virtual int ANSICodePage
120 get {
121 return data.ansi;
125 public virtual int EBCDICCodePage
127 get {
128 return data.ebcdic;
132 [ComVisible (false)]
133 public int LCID {
134 get { return m_win32LangID; }
137 public virtual string ListSeparator {
138 get {
139 if (m_listSeparator == null)
140 m_listSeparator = ((char) data.list_sep).ToString ();
141 return m_listSeparator;
143 [ComVisible (false)]
144 set { m_listSeparator = value; }
147 public virtual int MacCodePage
149 get {
150 return data.mac;
154 public virtual int OEMCodePage
156 get {
157 return data.oem;
161 [ComVisible (false)]
162 public string CultureName {
163 get {
164 if (customCultureName == null)
165 customCultureName = ci.Name;
166 return customCultureName;
170 [ComVisible (false)]
171 public bool IsReadOnly {
172 get { return m_isReadOnly; }
175 [ComVisible (false)]
176 public bool IsRightToLeft {
177 get {
178 // hardcoded
179 switch (m_win32LangID) {
180 case 1: // ar
181 case 13: // he
182 case 32: // ur
183 case 41: // fa
184 case 90: // syr
185 case 101: // div
186 case 1025: // ar-SA
187 case 1037: // he-IL
188 case 1056: // ur-PK
189 case 1065: // ra-IR
190 case 1114: // syr-SY
191 case 1125: // div-MV
192 case 2049: // ar-IQ
193 case 3073: // ar-EG
194 case 4097: // ar-LY
195 case 5121: // ar-DZ
196 case 6145: // ar-MA
197 case 7169: // ar-TN
198 case 8193: // ar-OM
199 case 9217: // ar-YE
200 case 10241: // ar-SY
201 case 11265: // ar-JO
202 case 12289: // ar-LB
203 case 13313: // ar-KW
204 case 14337: // ar-AE
205 case 15361: // ar-BH
206 case 16385: // ar-QA
207 return true;
208 default:
209 return false;
214 public override bool Equals (object obj)
216 if (obj == null)
217 return false;
218 TextInfo other = obj as TextInfo;
219 if (other == null)
220 return false;
221 if (other.m_win32LangID != m_win32LangID)
222 return false;
223 if (other.ci != ci)
224 return false;
225 return true;
228 public override int GetHashCode()
230 return (m_win32LangID);
233 public override string ToString()
235 return "TextInfo - " + m_win32LangID;
238 public string ToTitleCase (string str)
240 if(str == null)
241 throw new ArgumentNullException ("str");
243 StringBuilder sb = null;
244 int i = 0;
245 int start = 0;
246 while (i < str.Length) {
247 if (!Char.IsLetter (str [i++]))
248 continue;
249 i--;
250 char t = ToTitleCase (str [i]);
251 bool capitalize = true;
252 if (t == str [i]) {
253 capitalize = false;
254 bool allTitle = true;
255 // if the word is all titlecase,
256 // then don't capitalize it.
257 int saved = i;
258 while (++i < str.Length) {
259 if (Char.IsWhiteSpace (str [i]))
260 break;
261 t = ToTitleCase (str [i]);
262 if (t != str [i]) {
263 allTitle = false;
264 break;
267 if (allTitle)
268 continue;
269 i = saved;
271 // still check if all remaining
272 // characters are lowercase,
273 // where we don't have to modify
274 // the source word.
275 while (++i < str.Length) {
276 if (Char.IsWhiteSpace (str [i]))
277 break;
278 if (ToLower (str [i]) != str [i]) {
279 capitalize = true;
280 i = saved;
281 break;
286 if (capitalize) {
287 if (sb == null)
288 sb = new StringBuilder (str.Length);
289 sb.Append (str, start, i - start);
290 sb.Append (ToTitleCase (str [i]));
291 start = i + 1;
292 while (++i < str.Length) {
293 if (Char.IsWhiteSpace (str [i]))
294 break;
295 sb.Append (ToLower (str [i]));
297 start = i;
300 if (sb != null)
301 sb.Append (str, start, str.Length - start);
303 return sb != null ? sb.ToString () : str;
306 // Only Azeri and Turkish have their own special cases.
307 // Other than them, all languages have common special case
308 // (enumerable enough).
309 public virtual char ToLower (char c)
311 // quick ASCII range check
312 if (c < 0x40 || 0x60 < c && c < 128)
313 return c;
314 else if ('A' <= c && c <= 'Z' && (!handleDotI || c != 'I'))
315 return (char) (c + 0x20);
317 if (ci == null || ci.LCID == 0x7F)
318 return Char.ToLowerInvariant (c);
320 switch (c) {
321 case '\u0049': // Latin uppercase I
322 if (handleDotI)
323 return '\u0131'; // I becomes dotless i
324 break;
325 case '\u0130': // I-dotted
326 return '\u0069'; // i
328 case '\u01c5': // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
329 return '\u01c6';
330 // \u01c7 -> \u01c9 (LJ) : invariant
331 case '\u01c8': // LATIN CAPITAL LETTER L WITH SMALL LETTER J
332 return '\u01c9';
333 // \u01ca -> \u01cc (NJ) : invariant
334 case '\u01cb': // LATIN CAPITAL LETTER N WITH SMALL LETTER J
335 return '\u01cc';
336 // WITH CARON : invariant
337 // WITH DIAERESIS AND * : invariant
339 case '\u01f2': // LATIN CAPITAL LETTER D WITH SMALL LETTER Z
340 return '\u01f3';
341 case '\u03d2': // ? it is not in ICU
342 return '\u03c5';
343 case '\u03d3': // ? it is not in ICU
344 return '\u03cd';
345 case '\u03d4': // ? it is not in ICU
346 return '\u03cb';
348 return Char.ToLowerInvariant (c);
351 public virtual char ToUpper (char c)
353 // quick ASCII range check
354 if (c < 0x60)
355 return c;
356 else if ('a' <= c && c <= 'z' && (!handleDotI || c != 'i'))
357 return (char) (c - 0x20);
359 if (ci == null || ci.LCID == 0x7F)
360 return Char.ToUpperInvariant (c);
362 switch (c) {
363 case '\u0069': // Latin lowercase i
364 if (handleDotI)
365 return '\u0130'; // dotted capital I
366 break;
367 case '\u0131': // dotless i
368 return '\u0049'; // I
370 case '\u01c5': // see ToLower()
371 return '\u01c4';
372 case '\u01c8': // see ToLower()
373 return '\u01c7';
374 case '\u01cb': // see ToLower()
375 return '\u01ca';
376 case '\u01f2': // see ToLower()
377 return '\u01f1';
378 case '\u0390': // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
379 return '\u03aa'; // it is not in ICU
380 case '\u03b0': // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
381 return '\u03ab'; // it is not in ICU
382 case '\u03d0': // GREEK BETA
383 return '\u0392';
384 case '\u03d1': // GREEK THETA
385 return '\u0398';
386 case '\u03d5': // GREEK PHI
387 return '\u03a6';
388 case '\u03d6': // GREEK PI
389 return '\u03a0';
390 case '\u03f0': // GREEK KAPPA
391 return '\u039a';
392 case '\u03f1': // GREEK RHO
393 return '\u03a1';
394 // am not sure why miscellaneous GREEK symbols are
395 // not handled here.
398 return Char.ToUpperInvariant (c);
401 private char ToTitleCase (char c)
403 // Handle some Latin characters.
404 switch (c) {
405 case '\u01c4':
406 case '\u01c5':
407 case '\u01c6':
408 return '\u01c5';
409 case '\u01c7':
410 case '\u01c8':
411 case '\u01c9':
412 return '\u01c8';
413 case '\u01ca':
414 case '\u01cb':
415 case '\u01cc':
416 return '\u01cb';
417 case '\u01f1':
418 case '\u01f2':
419 case '\u01f3':
420 return '\u01f2';
422 if ('\u2170' <= c && c <= '\u217f' || // Roman numbers
423 '\u24d0' <= c && c <= '\u24e9')
424 return c;
425 return ToUpper (c);
428 public unsafe virtual string ToLower (string str)
430 // In ICU (3.2) there are a few cases that one single
431 // character results in multiple characters in e.g.
432 // tr-TR culture. So I tried brute force conversion
433 // test with single character as a string input, but
434 // there was no such conversion. So I think it just
435 // invokes ToLower(char).
436 if (str == null)
437 throw new ArgumentNullException ("str");
439 if (str.Length == 0)
440 return String.Empty;
442 string tmp = String.InternalAllocateStr (str.Length);
443 fixed (char* source = str, dest = tmp) {
445 char* destPtr = (char*)dest;
446 char* sourcePtr = (char*)source;
448 for (int n = 0; n < str.Length; n++) {
449 *destPtr = ToLower (*sourcePtr);
450 sourcePtr++;
451 destPtr++;
454 return tmp;
457 public unsafe virtual string ToUpper (string str)
459 // In ICU (3.2) there is a case that string
460 // is handled beyond per-character conversion, but
461 // it is only lt-LT culture where MS.NET does not
462 // handle any special transliteration. So I keep
463 // ToUpper() just as character conversion.
464 if (str == null)
465 throw new ArgumentNullException ("str");
467 if (str.Length == 0)
468 return String.Empty;
470 string tmp = String.InternalAllocateStr (str.Length);
471 fixed (char* source = str, dest = tmp) {
473 char* destPtr = (char*)dest;
474 char* sourcePtr = (char*)source;
476 for (int n = 0; n < str.Length; n++) {
477 *destPtr = ToUpper (*sourcePtr);
478 sourcePtr++;
479 destPtr++;
482 return tmp;
485 [ComVisible (false)]
486 public static TextInfo ReadOnly (TextInfo textInfo)
488 if (textInfo == null)
489 throw new ArgumentNullException ("textInfo");
491 TextInfo ti = new TextInfo (textInfo);
492 ti.m_isReadOnly = true;
493 return ti;
496 /* IDeserialization interface */
497 [MonoTODO]
498 void IDeserializationCallback.OnDeserialization(object sender)
500 // FIXME: we need to re-create "data" in order to get most properties working
503 /* IClonable */
504 [ComVisible (false)]
505 public virtual object Clone ()
507 return new TextInfo (this);