2007-10-30 Atsushi Enomoto <atsushi@ximian.com>
[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.hi-ho.ne.jp)
9 //
10 // (C) 2002 Ximian, Inc (http://www.ximian.com)
11 //
12
13 //
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 // 
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 // 
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 using System;
34 using System.IO;
35 using System.Text;
36 using System.Globalization;
37 using System.Xml.Schema;
38
39 namespace System.Xml {
40
41         public class XmlConvert {
42
43                 const string encodedColon = "_x003A_";
44                 const NumberStyles floatStyle = NumberStyles.AllowCurrencySymbol |
45                         NumberStyles.AllowExponent | 
46                         NumberStyles.AllowDecimalPoint |
47                         NumberStyles.AllowLeadingSign;
48                 
49                 static readonly string [] datetimeFormats = {
50                   // dateTime
51                   "yyyy-MM-ddTHH:mm:ss",
52                   "yyyy-MM-ddTHH:mm:ss.f",
53                   "yyyy-MM-ddTHH:mm:ss.ff",
54                   "yyyy-MM-ddTHH:mm:ss.fff",
55                   "yyyy-MM-ddTHH:mm:ss.ffff",
56                   "yyyy-MM-ddTHH:mm:ss.fffff",
57                   "yyyy-MM-ddTHH:mm:ss.ffffff",
58                   "yyyy-MM-ddTHH:mm:ss.fffffff",
59                   "yyyy-MM-ddTHH:mm:sszzz",
60                   "yyyy-MM-ddTHH:mm:ss.fzzz",
61                   "yyyy-MM-ddTHH:mm:ss.ffzzz",
62                   "yyyy-MM-ddTHH:mm:ss.fffzzz",
63                   "yyyy-MM-ddTHH:mm:ss.ffffzzz",
64                   "yyyy-MM-ddTHH:mm:ss.fffffzzz",
65                   "yyyy-MM-ddTHH:mm:ss.ffffffzzz",
66                   "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
67                   "yyyy-MM-ddTHH:mm:ssZ",
68                   "yyyy-MM-ddTHH:mm:ss.fZ",
69                   "yyyy-MM-ddTHH:mm:ss.ffZ",
70                   "yyyy-MM-ddTHH:mm:ss.fffZ",
71                   "yyyy-MM-ddTHH:mm:ss.ffffZ",
72                   "yyyy-MM-ddTHH:mm:ss.fffffZ",
73                   "yyyy-MM-ddTHH:mm:ss.ffffffZ",
74                   "yyyy-MM-ddTHH:mm:ss.fffffffZ",
75                   // time
76                   "HH:mm:ss",
77                   "HH:mm:ss.f",
78                   "HH:mm:ss.ff",
79                   "HH:mm:ss.fff",
80                   "HH:mm:ss.ffff",
81                   "HH:mm:ss.fffff",
82                   "HH:mm:ss.ffffff",
83                   "HH:mm:ss.fffffff",
84                   "HH:mm:sszzz",
85                   "HH:mm:ss.fzzz",
86                   "HH:mm:ss.ffzzz",
87                   "HH:mm:ss.fffzzz",
88                   "HH:mm:ss.ffffzzz",
89                   "HH:mm:ss.fffffzzz",
90                   "HH:mm:ss.ffffffzzz",
91                   "HH:mm:ss.fffffffzzz",
92                   "HH:mm:ssZ",
93                   "HH:mm:ss.fZ",
94                   "HH:mm:ss.ffZ",
95                   "HH:mm:ss.fffZ",
96                   "HH:mm:ss.ffffZ",
97                   "HH:mm:ss.fffffZ",
98                   "HH:mm:ss.ffffffZ",
99                   "HH:mm:ss.fffffffZ",
100                   // date
101                   "yyyy-MM-dd",
102                   "yyyy-MM-ddzzz",
103                   "yyyy-MM-ddZ",
104                   // gYearMonth
105                   "yyyy-MM",
106                   "yyyy-MMzzz",
107                   "yyyy-MMZ",
108                   // gYear
109                   "yyyy",
110                   "yyyyzzz",
111                   "yyyyZ",
112                   // gMonthDay
113                   "--MM-dd",
114                   "--MM-ddzzz",
115                   "--MM-ddZ",
116                   // gDay
117                   "---dd",
118                   "---ddzzz",
119                   "---ddZ",
120                 };
121                 
122                 public XmlConvert()
123                 {}
124
125                 private static string TryDecoding (string s)
126                 {
127                         if (s == null || s.Length < 6)
128                                 return s;
129
130                         char c = '\uFFFF';
131                         try {
132                                 c = (char) Int32.Parse (s.Substring (1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
133                         } catch {
134                                 return s [0] + DecodeName (s.Substring (1));
135                         }
136                         
137                         if (s.Length == 6)
138                                 return c.ToString ();
139                         return c + DecodeName (s.Substring (6));
140                 }
141                 
142                 public static string DecodeName (string name)
143                 {
144                         if (name == null || name.Length == 0)
145                                 return name;
146
147                         int pos = name.IndexOf ('_');
148                         if (pos == -1 || pos + 6 >= name.Length)
149                                 return name;
150
151                         if ((name [pos + 1] != 'X' && name [pos + 1] != 'x') || name [pos + 6] != '_')
152                                 return name [0] + DecodeName (name.Substring (1));
153
154                         return name.Substring (0, pos) + TryDecoding (name.Substring (pos + 1));
155                 }
156
157                 public static string EncodeLocalName (string name)
158                 {
159                         if (name == null)
160                                 return name;
161
162                         string encoded = EncodeName (name);
163                         int pos = encoded.IndexOf (':');
164                         if (pos == -1)
165                                 return encoded;
166                         return encoded.Replace (":", encodedColon);
167                 }
168
169                 internal static bool IsInvalid (char c, bool firstOnlyLetter)
170                 {
171                         if (c == ':') // Special case. allowed in EncodeName, but encoded in EncodeLocalName
172                                 return false;
173                         
174                         if (firstOnlyLetter)
175                                 return !XmlChar.IsFirstNameChar (c);
176                         else
177                                 return !XmlChar.IsNameChar (c);
178                 }
179
180                 private static string EncodeName (string name, bool nmtoken)
181                 {
182                         if (name == null || name.Length == 0)
183                                 return name;
184
185                         StringBuilder sb = new StringBuilder ();
186                         int length = name.Length;
187                         for (int i = 0; i < length; i++) {
188                                 char c = name [i];
189                                 if (IsInvalid (c, i == 0 && !nmtoken))
190                                         sb.AppendFormat ("_x{0:X4}_", (int) c);
191                                 else if (c == '_' && i + 6 < length && name [i+1] == 'x' && name [i + 6] == '_')
192                                         sb.Append ("_x005F_");
193                                 else
194                                         sb.Append (c);
195                         }
196                         return sb.ToString ();
197                 }
198
199                 public static string EncodeName (string name)
200                 {
201                         return EncodeName (name, false);
202                 }
203                 
204                 public static string EncodeNmToken (string name)
205                 {
206                         if (name == String.Empty)
207                                 throw new XmlException ("Invalid NmToken: ''");
208                         return EncodeName (name, true);
209                 }
210
211                 // {true, false, 1, 0}
212                 public static bool ToBoolean(string s)
213                 {
214                         s = s.Trim (XmlChar.WhitespaceChars);
215                         switch(s)
216                         {
217                                 case "1":
218                                         return true;
219                                 case "true":
220                                         return true;
221                                 case "0":
222                                         return false;
223                                 case "false":
224                                         return false;
225                                 default:
226                                         throw new FormatException(s + " is not a valid boolean value");
227                         }
228                 }
229
230                 // LAMESPEC: It has been documented as public, but is marked as internal.
231                 internal static string ToBinHexString (byte [] buffer)
232                 {
233                         StringWriter w = new StringWriter ();
234                         WriteBinHex (buffer, 0, buffer.Length, w);
235                         return w.ToString ();
236                 }
237
238                 internal static void WriteBinHex (byte [] buffer, int index, int count, TextWriter w)
239                 {
240                         if (buffer == null)
241                                 throw new ArgumentNullException ("buffer");
242                         if (index < 0) {
243                                 throw new ArgumentOutOfRangeException (
244 #if !NET_2_1
245                                         "index", index,
246 #endif
247                                         "index must be non negative integer.");
248                         }
249                         if (count < 0) {
250                                 throw new ArgumentOutOfRangeException (
251 #if !NET_2_1
252                                         "count", count,
253 #endif
254                                         "count must be non negative integer.");
255                         }
256                         if (buffer.Length < index + count)
257                                 throw new ArgumentOutOfRangeException ("index and count must be smaller than the length of the buffer.");
258
259                         // Copied from XmlTextWriter.WriteBinHex ()
260                         int end = index + count;
261                         for (int i = index; i < end; i++) {
262                                 int val = buffer [i];
263                                 int high = val >> 4;
264                                 int low = val & 15;
265                                 if (high > 9)
266                                         w.Write ((char) (high + 55));
267                                 else
268                                         w.Write ((char) (high + 0x30));
269                                 if (low > 9)
270                                         w.Write ((char) (low + 55));
271                                 else
272                                         w.Write ((char) (low + 0x30));
273                         }
274                 }
275
276                 public static byte ToByte(string s)
277                 {
278                         return Byte.Parse(s, CultureInfo.InvariantCulture);
279                 }
280
281                 public static char ToChar(string s)
282                 {
283                         return Char.Parse(s);
284                 }
285
286 #if NET_2_0
287                 [Obsolete]
288 #endif
289                 public static DateTime ToDateTime (string s)
290                 {
291                         return ToDateTime (s, datetimeFormats);
292                 }
293                 
294 #if NET_2_0
295                 public static DateTime ToDateTime (string value, XmlDateTimeSerializationMode mode)
296                 {
297                         string modestr = null;
298                         DateTime dt;
299                         switch (mode) {
300                         case XmlDateTimeSerializationMode.Local:
301                                 dt = ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz");
302                                 return dt == DateTime.MinValue || dt == DateTime.MaxValue ? dt : dt.ToLocalTime ();
303                         case XmlDateTimeSerializationMode.RoundtripKind:
304                                 return ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.FFFFFFFK");
305                         case XmlDateTimeSerializationMode.Utc:
306                                 dt = ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ");
307                                 return dt == DateTime.MinValue || dt == DateTime.MaxValue ? dt : dt.ToUniversalTime ();
308                         case XmlDateTimeSerializationMode.Unspecified:
309                         default:
310                                 return ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.FFFFFFF");
311                         }
312                 }
313 #endif
314                 public static DateTime ToDateTime(string s, string format)
315                 {
316                         //DateTimeFormatInfo d = new DateTimeFormatInfo();
317                         //d.FullDateTimePattern = format;
318                         //return DateTime.Parse(s, d);
319                         DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
320                                                DateTimeStyles.AllowTrailingWhite;
321                         return DateTime.ParseExact (s, format, DateTimeFormatInfo.InvariantInfo, style);
322                 }
323
324                 public static DateTime ToDateTime(string s, string[] formats)
325                 {
326                         DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
327                                                DateTimeStyles.AllowTrailingWhite;
328                         return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
329                 }
330                 
331                 public static Decimal ToDecimal(string s)
332                 {
333                         return Decimal.Parse(s, CultureInfo.InvariantCulture);
334                 }
335
336                 public static double ToDouble(string s)
337                 {
338                         if (s == null)
339                                 throw new ArgumentNullException();
340                         if (s == "INF")
341                                 return Double.PositiveInfinity;
342                         if (s == "-INF")
343                                 return Double.NegativeInfinity;
344                         if (s == "NaN")
345                                 return Double.NaN;
346                         return Double.Parse (s, floatStyle, CultureInfo.InvariantCulture);
347                 }
348
349                 public static Guid ToGuid(string s)
350                 {
351                         return new Guid(s);
352                 }
353
354                 public static short ToInt16(string s)
355                 {
356                         return Int16.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
357                 }
358
359                 public static int ToInt32(string s)
360                 {
361                         return Int32.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
362                 }
363
364                 public static long ToInt64(string s)
365                 {
366                         return Int64.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
367                 }
368
369                 [CLSCompliant (false)]
370                 public static SByte ToSByte(string s)
371                 {
372                         return SByte.Parse(s, CultureInfo.InvariantCulture);
373                 }
374
375                 public static float ToSingle(string s)
376                 {
377                         if (s == null)
378                                 throw new ArgumentNullException();
379                         if (s == "INF")
380                                 return Single.PositiveInfinity;
381                         if (s == "-INF")
382                                 return Single.NegativeInfinity;
383                         if (s == "NaN")
384                                 return Single.NaN;
385                         return Single.Parse(s, floatStyle, CultureInfo.InvariantCulture);
386                 }
387
388                 public static string ToString(Guid value)
389                 {
390                         return value.ToString("D", CultureInfo.InvariantCulture);
391                 }
392
393                 public static string ToString(int value)
394                 {
395                         return value.ToString(CultureInfo.InvariantCulture);
396                 }
397
398                 public static string ToString(short value)
399                 {
400                         return value.ToString(CultureInfo.InvariantCulture);
401                 }
402
403                 public static string ToString(byte value)
404                 {
405                         return value.ToString(CultureInfo.InvariantCulture);
406                 }
407
408                 public static string ToString(long value)
409                 {
410                         return value.ToString(CultureInfo.InvariantCulture);
411                 }
412
413                 public static string ToString(char value)
414                 {
415                         return value.ToString(CultureInfo.InvariantCulture);
416                 }
417
418                 public static string ToString(bool value)
419                 {
420                         if (value) return "true";
421                         return "false";
422                 }
423
424                 [CLSCompliant (false)]
425                 public static string ToString(SByte value)
426                 {
427                         return value.ToString(CultureInfo.InvariantCulture);
428                 }
429
430                 public static string ToString(Decimal value)
431                 {
432                         return value.ToString (CultureInfo.InvariantCulture);
433                 }
434
435                 [CLSCompliant (false)]
436                 public static string ToString(UInt64 value)
437                 {
438                         return value.ToString(CultureInfo.InvariantCulture);
439                 }
440
441                 public static string ToString (TimeSpan value)
442                 {
443                         if (value == TimeSpan.Zero)
444                                 return "PT0S";
445
446                         StringBuilder builder = new StringBuilder ();
447                         if (value.Ticks < 0) {
448                                 builder.Append ('-');
449                                 value = value.Negate ();
450                         }
451                         builder.Append ('P');
452                         if (value.Days > 0)
453                                 builder.Append (value.Days).Append ('D');
454                         if (value.Days > 0 || value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
455                                 builder.Append('T');
456                                 if (value.Hours > 0)
457                                         builder.Append (value.Hours).Append ('H');
458                                 if (value.Minutes > 0) 
459                                         builder.Append (value.Minutes).Append ('M');
460                                 if (value.Seconds > 0 || value.Milliseconds > 0) {
461                                         builder.Append (value.Seconds);
462                                         long ticks = value.Ticks % TimeSpan.TicksPerMillisecond;
463                                         if (ticks > 0)
464                                                 builder.Append ('.').AppendFormat ("{0:0000000}", value.Ticks % TimeSpan.TicksPerSecond);
465                                         else if (value.Milliseconds > 0)
466                                                 builder.Append ('.').AppendFormat ("{0:000}", value.Milliseconds);
467
468                                         builder.Append ('S');
469                                 }
470                         }
471                         return builder.ToString ();
472                 }
473
474                 public static string ToString(double value)
475                 {
476                         if (Double.IsNegativeInfinity(value)) return "-INF";
477                         if (Double.IsPositiveInfinity(value)) return "INF";
478                         if (Double.IsNaN(value)) return "NaN";
479                         return value.ToString(CultureInfo.InvariantCulture);
480                 }
481
482                 public static string ToString(float value)
483                 {
484                         if (Single.IsNegativeInfinity(value)) return "-INF";
485                         if (Single.IsPositiveInfinity(value)) return "INF";
486                         if (Single.IsNaN(value)) return "NaN";
487                         return value.ToString(CultureInfo.InvariantCulture);
488                 }
489
490                 [CLSCompliant (false)]
491                 public static string ToString(UInt32 value)
492                 {
493                         return value.ToString(CultureInfo.InvariantCulture);
494                 }
495
496                 [CLSCompliant (false)]
497                 public static string ToString(UInt16 value)
498                 {
499                         return value.ToString(CultureInfo.InvariantCulture);
500                 }
501
502 #if NET_2_0
503                 [Obsolete]
504 #endif
505                 public static string ToString (DateTime value)
506                 {
507                         return value.ToString ("yyyy-MM-ddTHH:mm:ss.fffffffzzz", CultureInfo.InvariantCulture);
508                 }
509
510 #if NET_2_0
511                 public static string ToString (DateTime value, XmlDateTimeSerializationMode mode)
512                 {
513                         // Unlike usual DateTime formatting, it preserves
514                         // MaxValue/MinValue as is.
515                         string modestr = null;
516                         switch (mode) {
517                         case XmlDateTimeSerializationMode.Local:
518                                 return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToLocalTime ()).ToString (
519                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
520                                         CultureInfo.InvariantCulture);
521                                 break;
522                         case XmlDateTimeSerializationMode.RoundtripKind:
523                                 return value.ToString (
524                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
525                                         CultureInfo.InvariantCulture);
526                                 break;
527                         default:
528                                 return value.ToString (
529                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
530                                         CultureInfo.InvariantCulture);
531                                 break;
532                         case XmlDateTimeSerializationMode.Utc:
533                                 return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToUniversalTime ()).ToString (
534                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",
535                                         CultureInfo.InvariantCulture);
536                                 break;
537                         case XmlDateTimeSerializationMode.Unspecified:
538                                 return value.ToString (
539                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
540                                         CultureInfo.InvariantCulture);
541                                 break;
542                         }
543                 }
544 #endif
545
546                 public static string ToString(DateTime value, string format)
547                 {
548                         return value.ToString(format, CultureInfo.InvariantCulture);
549                 }
550
551                 public static TimeSpan ToTimeSpan(string s)
552                 {
553                         if (s.Length == 0)
554                                 throw new ArgumentException ("Invalid format string for duration schema datatype.");
555
556                         int start = 0;
557                         if (s [0] == '-')
558                                 start = 1;
559                         bool minusValue = (start == 1);
560
561                         if (s [start] != 'P')
562                                 throw new ArgumentException ("Invalid format string for duration schema datatype.");
563                         start++;
564
565                         int parseStep = 0;
566                         int days = 0;
567                         bool isTime = false;
568                         int hours = 0;
569                         int minutes = 0;
570                         int seconds = 0;
571                         long ticks = 0;
572                         int parsedDigits = 0;
573
574                         bool error = false;
575
576                         int i = start;
577                         while (i < s.Length) {
578                                 if (s [i] == 'T') {
579                                         isTime = true;
580                                         parseStep = 4;
581                                         i++;
582                                         start = i;
583                                         continue;
584                                 }
585                                 for (; i < s.Length; i++)
586                                         if (s [i] < '0' || '9' < s [i])
587                                                 break;
588                                 if (parseStep == 7)
589                                         parsedDigits = i - start;
590                                 int value = int.Parse (s.Substring (start, i - start), CultureInfo.InvariantCulture);
591                                 if (parseStep == 7) {
592                                         // adjust to 7 digits so that it makes sense as millisecond digits
593                                         for (; parsedDigits > 7; parsedDigits--)
594                                                 value /= 10;
595                                         for (; parsedDigits < 7; parsedDigits++)
596                                                 value *= 10;
597                                 }
598                                 switch (s [i]) {
599                                 case 'Y':
600                                         days += value * 365;
601                                         if (parseStep > 0)
602                                                 error = true;
603                                         else
604                                                 parseStep = 1;
605                                         break;
606                                 case 'M':
607                                         if (parseStep < 2) {
608                                                 days += 365 * (value / 12) + 30 * (value % 12);
609                                                 parseStep = 2;
610                                         } else if (isTime && parseStep < 6) {
611                                                 minutes = value;
612                                                 parseStep = 6;
613                                         }
614                                         else
615                                                 error = true;
616                                         break;
617                                 case 'D':
618                                         days += value;
619                                         if (parseStep > 2)
620                                                 error = true;
621                                         else
622                                                 parseStep = 3;
623                                         break;
624                                 case 'H':
625                                         hours = value;
626                                         if (!isTime || parseStep > 4)
627                                                 error = true;
628                                         else
629                                                 parseStep = 5;
630                                         break;
631                                 case 'S':
632                                         if (parseStep == 7)
633                                                 ticks = value;
634                                         else
635                                                 seconds = value;
636                                         if (!isTime || parseStep > 7)
637                                                 error = true;
638                                         else
639                                                 parseStep = 8;
640                                         break;
641                                 case '.':
642                                         if (parseStep > 7)
643                                                 error = true;
644                                         seconds = value;
645                                         parseStep = 7;
646                                         break;
647                                 default:
648                                         error = true;
649                                         break;
650                                 }
651                                 if (error)
652                                         break;
653                                 ++i;
654                                 start = i;
655                         }
656                         if (error)
657                                 throw new ArgumentException ("Invalid format string for duration schema datatype.");
658                         TimeSpan ts = new TimeSpan (days, hours, minutes, seconds);
659                         if (minusValue)
660                                 return TimeSpan.FromTicks (- (ts.Ticks + ticks));
661                         else
662                                 return TimeSpan.FromTicks (ts.Ticks + ticks);
663                 }
664
665                 [CLSCompliant (false)]
666                 public static UInt16 ToUInt16(string s)
667                 {
668                         return UInt16.Parse(s, CultureInfo.InvariantCulture);
669                 }
670
671                 [CLSCompliant (false)]
672                 public static UInt32 ToUInt32(string s)
673                 {
674                         return UInt32.Parse(s, CultureInfo.InvariantCulture);
675                 }
676
677                 [CLSCompliant (false)]
678                 public static UInt64 ToUInt64(string s)
679                 {
680                         return UInt64.Parse(s, CultureInfo.InvariantCulture);
681                 }
682
683                 public static string VerifyName (string name)
684                 {
685                         if (name == null || name.Length == 0)
686                                 throw new ArgumentNullException("name");
687
688                         if (!XmlChar.IsName (name))
689                                 throw new XmlException("'" + name + "' is not a valid XML Name");
690                         return name;
691                         
692                 }
693
694                 public static string VerifyNCName (string ncname)
695                 {
696                         if (ncname == null || ncname.Length == 0)
697                                 throw new ArgumentNullException("ncname");
698
699                         if (!XmlChar.IsNCName (ncname))
700                                 throw new XmlException ("'" + ncname + "' is not a valid XML NCName");
701                         return ncname;
702                 }
703
704 #if NET_2_0
705                 public static string VerifyTOKEN (string name)
706 #else
707                 internal static string VerifyTOKEN (string name)
708 #endif
709                 {
710                         if (name == null)
711                                 throw new ArgumentNullException("name");
712
713                         if (name.Length == 0)
714                                 return name;
715
716                         if (XmlChar.IsWhitespace (name [0]) ||
717                                 XmlChar.IsWhitespace (name [name.Length - 1]))
718                                 throw new XmlException ("Whitespace characters (#xA, #xD, #x9, #x20) are not allowed as leading or trailing whitespaces of xs:token.");
719
720                         for (int i = 0; i < name.Length; i++)
721                                 if (XmlChar.IsWhitespace (name [i]) && name [i] != ' ')
722                                 throw new XmlException ("Either #xA, #xD or #x9 are not allowed inside xs:token.");
723
724                         return name;
725                 }
726
727 #if NET_2_0
728                 public static string VerifyNMTOKEN (string name)
729 #else
730                 internal static string VerifyNMTOKEN (string name)
731 #endif
732                 {
733                         if (name == null)
734                                 throw new ArgumentNullException("name");
735
736                         if (!XmlChar.IsNmToken (name))
737                                 throw new XmlException("'" + name + "' is not a valid XML NMTOKEN");
738                         return name;
739                         
740                 }
741
742                 // It is documented as public method, but in fact it is not.
743                 internal static byte [] FromBinHexString (string s)
744                 {
745                         char [] chars = s.ToCharArray ();
746                         byte [] bytes = new byte [chars.Length / 2 + chars.Length % 2];
747                         FromBinHexString (chars, 0, chars.Length, bytes);
748                         return bytes;
749                 }
750
751                 internal static int FromBinHexString (char [] chars, int offset, int charLength, byte [] buffer)
752                 {
753                         int bufIndex = offset;
754                         for (int i = 0; i < charLength - 1; i += 2) {
755                                 buffer [bufIndex] = (chars [i] > '9' ?
756                                                 (byte) (chars [i] - 'A' + 10) :
757                                                 (byte) (chars [i] - '0'));
758                                 buffer [bufIndex] <<= 4;
759                                 buffer [bufIndex] += chars [i + 1] > '9' ?
760                                                 (byte) (chars [i + 1] - 'A' + 10) : 
761                                                 (byte) (chars [i + 1] - '0');
762                                 bufIndex++;
763                         }
764                         if (charLength %2 != 0)
765                                 buffer [bufIndex++] = (byte)
766                                         ((chars [charLength - 1] > '9' ?
767                                                 (byte) (chars [charLength - 1] - 'A' + 10) :
768                                                 (byte) (chars [charLength - 1] - '0'))
769                                         << 4);
770
771                         return bufIndex - offset;
772                 }
773         }
774 }