2 // System.Globalization.TextInfo.cs
5 // Dick Porter (dick@ximian.com)
6 // Duncan Mak (duncan@ximian.com)
7 // Atsushi Enomoto (atsushi@ximian.com)
8 // Sebastien Pouliot <sebastien@ximian.com>
10 // (C) 2002 Ximian, Inc.
11 // (C) 2005 Novell, Inc.
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:
27 // The above copyright notice and this permission notice shall be
28 // included in all copies or substantial portions of the Software.
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
;
43 namespace System
.Globalization
{
47 [MonoTODO ("IDeserializationCallback isn't implemented.")]
48 public class TextInfo
: IDeserializationCallback
, ICloneable
50 [StructLayout (LayoutKind
.Sequential
)]
59 string m_listSeparator
;
61 string customCultureName
;
63 #pragma warning disable 169
66 bool m_useUserOverride
;
67 #pragma warning restore 169
72 readonly CultureInfo ci
;
75 readonly bool handleDotI
;
80 internal unsafe TextInfo (CultureInfo ci
, int lcid
, void* data
, bool read_only
)
82 this.m_isReadOnly
= read_only
;
83 this.m_win32LangID
= lcid
;
86 this.data
= *(Data
*) data
;
88 this.data
= new Data ();
89 this.data
.list_sep
= (byte) ',';
93 while (tmp
.Parent
!= null && tmp
.Parent
.LCID
!= 0x7F && tmp
.Parent
!= tmp
)
98 case 44: // Azeri (az)
99 case 31: // Turkish (tr)
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
;
114 handleDotI
= textInfo
.handleDotI
;
115 data
= textInfo
.data
;
118 public virtual int ANSICodePage
125 public virtual int EBCDICCodePage
134 get { return m_win32LangID; }
137 public virtual string ListSeparator
{
139 if (m_listSeparator
== null)
140 m_listSeparator
= ((char) data
.list_sep
).ToString ();
141 return m_listSeparator
;
144 set { m_listSeparator = value; }
147 public virtual int MacCodePage
154 public virtual int OEMCodePage
162 public string CultureName
{
164 if (customCultureName
== null)
165 customCultureName
= ci
.Name
;
166 return customCultureName
;
171 public bool IsReadOnly
{
172 get { return m_isReadOnly; }
176 public bool IsRightToLeft
{
179 switch (m_win32LangID
) {
214 public override bool Equals (object obj
)
218 TextInfo other
= obj
as TextInfo
;
221 if (other
.m_win32LangID
!= m_win32LangID
)
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
)
241 throw new ArgumentNullException ("str");
243 StringBuilder sb
= null;
246 while (i
< str
.Length
) {
247 if (!Char
.IsLetter (str
[i
++]))
250 char t
= ToTitleCase (str
[i
]);
251 bool capitalize
= true;
254 bool allTitle
= true;
255 // if the word is all titlecase,
256 // then don't capitalize it.
258 while (++i
< str
.Length
) {
259 if (Char
.IsWhiteSpace (str
[i
]))
261 t
= ToTitleCase (str
[i
]);
271 // still check if all remaining
272 // characters are lowercase,
273 // where we don't have to modify
275 while (++i
< str
.Length
) {
276 if (Char
.IsWhiteSpace (str
[i
]))
278 if (ToLower (str
[i
]) != str
[i
]) {
288 sb
= new StringBuilder (str
.Length
);
289 sb
.Append (str
, start
, i
- start
);
290 sb
.Append (ToTitleCase (str
[i
]));
292 while (++i
< str
.Length
) {
293 if (Char
.IsWhiteSpace (str
[i
]))
295 sb
.Append (ToLower (str
[i
]));
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)
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
);
321 case '\u0049': // Latin uppercase I
323 return '\u0131'; // I becomes dotless i
325 case '\u0130': // I-dotted
326 return '\u0069'; // i
328 case '\u01c5': // LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
330 // \u01c7 -> \u01c9 (LJ) : invariant
331 case '\u01c8': // LATIN CAPITAL LETTER L WITH SMALL LETTER J
333 // \u01ca -> \u01cc (NJ) : invariant
334 case '\u01cb': // LATIN CAPITAL LETTER N WITH SMALL LETTER J
336 // WITH CARON : invariant
337 // WITH DIAERESIS AND * : invariant
339 case '\u01f2': // LATIN CAPITAL LETTER D WITH SMALL LETTER Z
341 case '\u03d2': // ? it is not in ICU
343 case '\u03d3': // ? it is not in ICU
345 case '\u03d4': // ? it is not in ICU
348 return Char
.ToLowerInvariant (c
);
351 public virtual char ToUpper (char c
)
353 // quick ASCII range check
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
);
363 case '\u0069': // Latin lowercase i
365 return '\u0130'; // dotted capital I
367 case '\u0131': // dotless i
368 return '\u0049'; // I
370 case '\u01c5': // see ToLower()
372 case '\u01c8': // see ToLower()
374 case '\u01cb': // see ToLower()
376 case '\u01f2': // see ToLower()
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
384 case '\u03d1': // GREEK THETA
386 case '\u03d5': // GREEK PHI
388 case '\u03d6': // GREEK PI
390 case '\u03f0': // GREEK KAPPA
392 case '\u03f1': // GREEK RHO
394 // am not sure why miscellaneous GREEK symbols are
398 return Char
.ToUpperInvariant (c
);
401 private char ToTitleCase (char c
)
403 // Handle some Latin characters.
422 if ('\u2170' <= c
&& c
<= '\u217f' || // Roman numbers
423 '\u24d0' <= c
&& c
<= '\u24e9')
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).
437 throw new ArgumentNullException ("str");
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
);
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.
465 throw new ArgumentNullException ("str");
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
);
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;
496 /* IDeserialization interface */
498 void IDeserializationCallback
.OnDeserialization(object sender
)
500 // FIXME: we need to re-create "data" in order to get most properties working
505 public virtual object Clone ()
507 return new TextInfo (this);