2003-10-19 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml / XmlConvert.cs
1 //
2 // System.Xml.XmlConvert
3 //
4 // Authors:
5 //      Dwivedi, Ajay kumar (Adwiv@Yahoo.com)
6 //      Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //      Alan Tam Siu Lung (Tam@SiuLung.com)
8 //      Atsushi Enomoto (ginga@kit.h-ho.ne.jp)
9 //
10 // (C) 2002 Ximian, Inc (http://www.ximian.com)
11 //
12 using System;
13 using System.Text;
14 using System.Globalization;
15
16 namespace System.Xml {
17
18         public class XmlConvert {
19
20                 static string encodedColon = "_x003A_";
21
22                 public XmlConvert()
23                 {}
24
25                 private static string TryDecoding (string s)
26                 {
27                         if (s == null || s.Length < 6)
28                                 return s;
29
30                         char c = '\uFFFF';
31                         try {
32                                 c = (char) Int32.Parse (s.Substring (1, 4), NumberStyles.HexNumber);
33                         } catch {
34                                 return s [0] + DecodeName (s.Substring (1));
35                         }
36                         
37                         if (s.Length == 6)
38                                 return c.ToString ();
39                         return c + DecodeName (s.Substring (6));
40                 }
41                 
42                 public static string DecodeName (string name)
43                 {
44                         if (name == null || name.Length == 0)
45                                 return name;
46
47                         int pos = name.IndexOf ('_');
48                         if (pos == -1 || pos + 6 >= name.Length)
49                                 return name;
50
51                         if (Char.ToUpper (name [pos + 1]) != 'X' || name [pos + 6] != '_')
52                                 return name [0] + DecodeName (name.Substring (1));
53
54                         return name.Substring (0, pos) + TryDecoding (name.Substring (pos + 1));
55                 }
56
57                 public static string EncodeLocalName (string name)
58                 {
59                         string encoded = EncodeName (name);
60                         int pos = encoded.IndexOf (':');
61                         if (pos == -1)
62                                 return encoded;
63                         return encoded.Replace (":", encodedColon);
64                 }
65
66                 internal static bool IsInvalid (char c, bool firstOnlyLetter)
67                 {
68                         if (c == ':') // Special case. allowed in EncodeName, but encoded in EncodeLocalName
69                                 return false;
70                         
71                         if (firstOnlyLetter)
72                                 return !XmlChar.IsFirstNameChar (c);
73                         else
74                                 return !XmlChar.IsNameChar (c);
75                 }
76
77                 private static string EncodeName (string name, bool nmtoken)
78                 {
79                         StringBuilder sb = new StringBuilder ();
80                         int length = name.Length;
81                         for (int i = 0; i < length; i++) {
82                                 char c = name [i];
83                                 if (IsInvalid (c, i == 0 && !nmtoken))
84                                         sb.AppendFormat ("_x{0:X4}_", (int) c);
85                                 else if (c == '_' && i + 6 < length && name [i+1] == 'x' && name [i + 6] == '_')
86                                         sb.Append ("_x005F_");
87                                 else
88                                         sb.Append (c);
89                         }
90                         return sb.ToString ();
91                 }
92
93                 public static string EncodeName (string name)
94                 {
95                         return EncodeName (name, false);
96                 }
97                 
98                 public static string EncodeNmToken(string name)
99                 {
100                         return EncodeName (name, true);
101                 }
102
103                 // {true, false, 1, 0}
104                 public static bool ToBoolean(string s)
105                 {
106                         s = s.Trim (XmlChar.WhitespaceChars);
107                         switch(s)
108                         {
109                                 case "1":
110                                         return true;
111                                 case "true":
112                                         return true;
113                                 case "0":
114                                         return false;
115                                 case "false":
116                                         return false;
117                                 default:
118                                         throw new FormatException(s + " is not a valid boolean value");
119                         }
120                 }
121
122                 public static byte ToByte(string s)
123                 {
124                         return Byte.Parse(s, CultureInfo.InvariantCulture);
125                 }
126
127                 public static char ToChar(string s)
128                 {
129                         return Char.Parse(s);
130                 }
131
132                 public static DateTime ToDateTime(string s)
133                 {
134                         return ToDateTime(s, new string[] {
135                           // dateTime
136                           "yyyy-MM-ddTHH:mm:ss",
137                           "yyyy-MM-ddTHH:mm:ss.f",
138                           "yyyy-MM-ddTHH:mm:ss.ff",
139                           "yyyy-MM-ddTHH:mm:ss.fff",
140                           "yyyy-MM-ddTHH:mm:ss.ffff",
141                           "yyyy-MM-ddTHH:mm:ss.fffff",
142                           "yyyy-MM-ddTHH:mm:ss.ffffff",
143                           "yyyy-MM-ddTHH:mm:ss.fffffff",
144                           "yyyy-MM-ddTHH:mm:sszzz",
145                           "yyyy-MM-ddTHH:mm:ss.fzzz",
146                           "yyyy-MM-ddTHH:mm:ss.ffzzz",
147                           "yyyy-MM-ddTHH:mm:ss.fffzzz",
148                           "yyyy-MM-ddTHH:mm:ss.ffffzzz",
149                           "yyyy-MM-ddTHH:mm:ss.fffffzzz",
150                           "yyyy-MM-ddTHH:mm:ss.ffffffzzz",
151                           "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
152                           "yyyy-MM-ddTHH:mm:ssZ",
153                           "yyyy-MM-ddTHH:mm:ss.fZ",
154                           "yyyy-MM-ddTHH:mm:ss.ffZ",
155                           "yyyy-MM-ddTHH:mm:ss.fffZ",
156                           "yyyy-MM-ddTHH:mm:ss.ffffZ",
157                           "yyyy-MM-ddTHH:mm:ss.fffffZ",
158                           "yyyy-MM-ddTHH:mm:ss.ffffffZ",
159                           "yyyy-MM-ddTHH:mm:ss.fffffffZ",
160                           // time
161                           "HH:mm:ss",
162                           "HH:mm:ss.f",
163                           "HH:mm:ss.ff",
164                           "HH:mm:ss.fff",
165                           "HH:mm:ss.ffff",
166                           "HH:mm:ss.fffff",
167                           "HH:mm:ss.ffffff",
168                           "HH:mm:ss.fffffff",
169                           "HH:mm:sszzz",
170                           "HH:mm:ss.fzzz",
171                           "HH:mm:ss.ffzzz",
172                           "HH:mm:ss.fffzzz",
173                           "HH:mm:ss.ffffzzz",
174                           "HH:mm:ss.fffffzzz",
175                           "HH:mm:ss.ffffffzzz",
176                           "HH:mm:ss.fffffffzzz",
177                           "HH:mm:ssZ",
178                           "HH:mm:ss.fZ",
179                           "HH:mm:ss.ffZ",
180                           "HH:mm:ss.fffZ",
181                           "HH:mm:ss.ffffZ",
182                           "HH:mm:ss.fffffZ",
183                           "HH:mm:ss.ffffffZ",
184                           "HH:mm:ss.fffffffZ",
185                           // date
186                           "yyyy-MM-dd",
187                           "yyyy-MM-ddzzz",
188                           "yyyy-MM-ddZ",
189                           // gYearMonth
190                           "yyyy-MM",
191                           "yyyy-MMzzz",
192                           "yyyy-MMZ",
193                           // gYear
194                           "yyyy",
195                           "yyyyzzz",
196                           "yyyyZ",
197                           // gMonthDay
198                           "--MM-dd",
199                           "--MM-ddzzz",
200                           "--MM-ddZ",
201                           // gDay
202                           "---dd",
203                           "---ddzzz",
204                           "---ddZ",
205                         });
206                 }
207                 
208                 public static DateTime ToDateTime(string s, string format)
209                 {
210                         DateTimeFormatInfo d = new DateTimeFormatInfo();
211                         d.FullDateTimePattern = format;
212                         return DateTime.Parse(s, d);
213                 }
214
215                 public static DateTime ToDateTime(string s, string[] formats)
216                 {
217                         DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
218                                                DateTimeStyles.AllowTrailingWhite;
219                         return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
220                 }
221                 
222                 public static Decimal ToDecimal(string s)
223                 {
224                         return Decimal.Parse(s, CultureInfo.InvariantCulture);
225                 }
226                 
227                 public static double ToDouble(string s)
228                 {
229                         if (s == "INF") return System.Double.PositiveInfinity;
230                         if (s == "-INF") return System.Double.NegativeInfinity;
231                         if (s == "NaN") return System.Double.NaN;
232                         return Double.Parse(s, CultureInfo.InvariantCulture);
233                 }
234
235                 public static Guid ToGuid(string s)
236                 {
237                         return new Guid(s);
238                 }
239
240                 public static short ToInt16(string s)
241                 {
242                         return Int16.Parse(s, CultureInfo.InvariantCulture);
243                 }
244
245                 public static int ToInt32(string s)
246                 {
247                         return Int32.Parse(s, CultureInfo.InvariantCulture);
248                 }
249
250                 public static long ToInt64(string s)
251                 {
252                         return Int64.Parse(s, CultureInfo.InvariantCulture);
253                 }
254
255                 [CLSCompliant (false)]
256                 public static SByte ToSByte(string s)
257                 {
258                         return SByte.Parse(s, CultureInfo.InvariantCulture);
259                 }
260
261                 public static float ToSingle(string s)
262                 {
263                         if (s == "INF") return System.Single.PositiveInfinity;
264                         if (s == "-INF") return System.Single.NegativeInfinity;
265                         if (s == "NaN") return System.Single.NaN;
266                         return Single.Parse(s, CultureInfo.InvariantCulture);
267                 }
268
269                 public static string ToString(Guid value)
270                 {
271                         return value.ToString("D",CultureInfo.InvariantCulture);
272                 }
273
274                 public static string ToString(int value)
275                 {
276                         return value.ToString(CultureInfo.InvariantCulture);
277                 }
278
279                 public static string ToString(short value)
280                 {
281                         return value.ToString(CultureInfo.InvariantCulture);
282                 }
283
284                 public static string ToString(byte value)
285                 {
286                         return value.ToString(CultureInfo.InvariantCulture);
287                 }
288
289                 public static string ToString(long value)
290                 {
291                         return value.ToString(CultureInfo.InvariantCulture);
292                 }
293
294                 public static string ToString(char value)
295                 {
296                         return value.ToString(CultureInfo.InvariantCulture);
297                 }
298
299                 public static string ToString(bool value)
300                 {
301                         if (value) return "true";
302                         return "false";
303                 }
304
305                 [CLSCompliant (false)]
306                 public static string ToString(SByte value)
307                 {
308                         return value.ToString(CultureInfo.InvariantCulture);
309                 }
310
311                 public static string ToString(Decimal value)
312                 {
313                         return value.ToString(CultureInfo.InvariantCulture);
314                 }
315
316                 [CLSCompliant (false)]
317                 public static string ToString(UInt64 value)
318                 {
319                         return value.ToString(CultureInfo.InvariantCulture);
320                 }
321
322                 public static string ToString(TimeSpan value)
323                 {
324                         StringBuilder builder = new StringBuilder();
325                         if (value.Ticks < 0) {
326                                 builder.Append('-');
327                                 value = value.Negate();
328                         }
329                         builder.Append('P');
330                         if (value.Days > 0) builder.Append(value.Days).Append('D');
331                         if (value.Days > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
332                                 builder.Append('T');
333                                 if (value.Hours > 0) builder.Append(value.Hours).Append('D');
334                                 if (value.Minutes > 0) builder.Append(value.Minutes).Append('M');
335                                 if (value.Seconds > 0 || value.Milliseconds > 0) {
336                                         builder.Append(value.Seconds);
337                                         if (value.Milliseconds > 0) builder.Append('.').Append(String.Format("{0:000}", value.Milliseconds));
338                                         builder.Append('S');
339                                 }
340                         }
341                         return builder.ToString();
342                 }
343
344                 public static string ToString(double value)
345                 {
346                         if (Double.IsNegativeInfinity(value)) return "-INF";
347                         if (Double.IsPositiveInfinity(value)) return "INF";
348                         if (Double.IsNaN(value)) return "NaN";
349                         return value.ToString(CultureInfo.InvariantCulture);
350                 }
351
352                 public static string ToString(float value)
353                 {
354                         if (Single.IsNegativeInfinity(value)) return "-INF";
355                         if (Single.IsPositiveInfinity(value)) return "INF";
356                         if (Single.IsNaN(value)) return "NaN";
357                         return value.ToString(CultureInfo.InvariantCulture);
358                 }
359
360                 [CLSCompliant (false)]
361                 public static string ToString(UInt32 value)
362                 {
363                         return value.ToString(CultureInfo.InvariantCulture);
364                 }
365
366                 [CLSCompliant (false)]
367                 public static string ToString(UInt16 value)
368                 {
369                         return value.ToString(CultureInfo.InvariantCulture);
370                 }
371
372                 public static string ToString(DateTime value)
373                 {
374                         return value.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", CultureInfo.InvariantCulture);
375                 }
376
377                 public static string ToString(DateTime value, string format)
378                 {
379                         return value.ToString(format, CultureInfo.InvariantCulture);
380                 }
381
382                 [MonoTODO]
383                 public static TimeSpan ToTimeSpan(string s)
384                 {
385                         return TimeSpan.Parse(s); // FIXME: Should Parse according to XML Schema spec
386                 }
387
388                 [CLSCompliant (false)]
389                 public static UInt16 ToUInt16(string s)
390                 {
391                         return UInt16.Parse(s, CultureInfo.InvariantCulture);
392                 }
393
394                 [CLSCompliant (false)]
395                 public static UInt32 ToUInt32(string s)
396                 {
397                         return UInt32.Parse(s, CultureInfo.InvariantCulture);
398                 }
399
400                 [CLSCompliant (false)]
401                 public static UInt64 ToUInt64(string s)
402                 {
403                         return UInt64.Parse(s, CultureInfo.InvariantCulture);
404                 }
405
406                 public static string VerifyName (string name)
407                 {
408                         if(name == null)
409                                 throw new ArgumentNullException("name");
410
411                         if(!XmlChar.IsName (name))
412                                 throw new XmlException("'" + name + "' is not a valid XML Name");
413                         return name;
414                         
415                 }
416
417                 public static string VerifyNCName(string ncname)
418                 {
419                         if(ncname == null)
420                                 throw new ArgumentNullException("ncname");
421
422                         if(!XmlChar.IsNCName (ncname))
423                                 throw new XmlException ("'" + ncname + "' is not a valid XML NCName");
424                         return ncname;
425                 }
426
427                 // It is documented as public method, but in fact it is not.
428                 internal static byte [] FromBinHexString (string s)
429                 {
430                         char [] chars = s.ToCharArray ();
431                         byte [] bytes = new byte [chars.Length / 2 + chars.Length % 2];
432                         FromBinHexString (chars, 0, chars.Length, bytes);
433                         return bytes;
434                 }
435
436                 internal static int FromBinHexString (char [] chars, int offset, int charLength, byte [] buffer)
437                 {
438                         int bufIndex = offset;
439                         for (int i = 0; i < charLength - 1; i += 2) {
440                                 buffer [bufIndex] = (chars [i] > '9' ?
441                                                 (byte) (chars [i] - 'A' + 10) :
442                                                 (byte) (chars [i] - '0'));
443                                 buffer [bufIndex] <<= 4;
444                                 buffer [bufIndex] += chars [i + 1] > '9' ?
445                                                 (byte) (chars [i + 1] - 'A' + 10) : 
446                                                 (byte) (chars [i + 1] - '0');
447                                 bufIndex++;
448                         }
449                         if (charLength %2 != 0)
450                                 buffer [bufIndex++] = (byte)
451                                         ((chars [charLength - 1] > '9' ?
452                                                 (byte) (chars [charLength - 1] - 'A' + 10) :
453                                                 (byte) (chars [charLength - 1] - '0'))
454                                         << 4);
455
456                         return bufIndex - offset;
457                 }
458         }
459 }