for TARGET_J2EE only:
[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 #if NET_2_0
123                 static readonly string [] defaultDateTimeFormats = new string [] {
124                         "yyyy-MM-ddTHH:mm:ss", // dateTime(1)
125                         "yyyy-MM-ddTHH:mm:ss.FFFFFFF", // dateTime(2)
126                         "yyyy-MM-dd", // date
127                         "HH:mm:ss", // time
128                         "yyyy-MM", // gYearMonth
129                         "yyyy", // gYear
130                         "--MM-dd", // gMonthDay
131                         "---dd", // gDay
132                         };
133
134                 static readonly string [] roundtripDateTimeFormats;
135                 static readonly string [] localDateTimeFormats;
136                 static readonly string [] utcDateTimeFormats;
137
138                 static XmlConvert ()
139                 {
140                         int l = defaultDateTimeFormats.Length;
141                         roundtripDateTimeFormats = new string [l];
142                         localDateTimeFormats = new string [l];
143                         utcDateTimeFormats = new string [l];
144                         for (int i = 0; i < l; i++) {
145                                 string s = defaultDateTimeFormats [i];
146                                 localDateTimeFormats [i] = s + "zzz";
147                                 roundtripDateTimeFormats [i] = s + 'K';
148                                 utcDateTimeFormats [i] = s + 'Z';
149                         }
150                 }
151 #endif
152
153                 public XmlConvert()
154                 {}
155
156                 private static string TryDecoding (string s)
157                 {
158                         if (s == null || s.Length < 6)
159                                 return s;
160
161                         char c = '\uFFFF';
162                         try {
163                                 c = (char) Int32.Parse (s.Substring (1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
164                         } catch {
165                                 return s [0] + DecodeName (s.Substring (1));
166                         }
167                         
168                         if (s.Length == 6)
169                                 return c.ToString ();
170                         return c + DecodeName (s.Substring (6));
171                 }
172                 
173                 public static string DecodeName (string name)
174                 {
175                         if (name == null || name.Length == 0)
176                                 return name;
177
178                         int pos = name.IndexOf ('_');
179                         if (pos == -1 || pos + 6 >= name.Length)
180                                 return name;
181
182                         if ((name [pos + 1] != 'X' && name [pos + 1] != 'x') || name [pos + 6] != '_')
183                                 return name [0] + DecodeName (name.Substring (1));
184
185                         return name.Substring (0, pos) + TryDecoding (name.Substring (pos + 1));
186                 }
187
188                 public static string EncodeLocalName (string name)
189                 {
190                         if (name == null)
191                                 return name;
192
193                         string encoded = EncodeName (name);
194                         int pos = encoded.IndexOf (':');
195                         if (pos == -1)
196                                 return encoded;
197                         return encoded.Replace (":", encodedColon);
198                 }
199
200                 internal static bool IsInvalid (char c, bool firstOnlyLetter)
201                 {
202                         if (c == ':') // Special case. allowed in EncodeName, but encoded in EncodeLocalName
203                                 return false;
204                         
205                         if (firstOnlyLetter)
206                                 return !XmlChar.IsFirstNameChar (c);
207                         else
208                                 return !XmlChar.IsNameChar (c);
209                 }
210
211                 private static string EncodeName (string name, bool nmtoken)
212                 {
213                         if (name == null || name.Length == 0)
214                                 return name;
215
216                         StringBuilder sb = new StringBuilder ();
217                         int length = name.Length;
218                         for (int i = 0; i < length; i++) {
219                                 char c = name [i];
220                                 if (IsInvalid (c, i == 0 && !nmtoken))
221                                         sb.AppendFormat ("_x{0:X4}_", (int) c);
222                                 else if (c == '_' && i + 6 < length && name [i+1] == 'x' && name [i + 6] == '_')
223                                         sb.Append ("_x005F_");
224                                 else
225                                         sb.Append (c);
226                         }
227                         return sb.ToString ();
228                 }
229
230                 public static string EncodeName (string name)
231                 {
232                         return EncodeName (name, false);
233                 }
234                 
235                 public static string EncodeNmToken (string name)
236                 {
237                         if (name == String.Empty)
238                                 throw new XmlException ("Invalid NmToken: ''");
239                         return EncodeName (name, true);
240                 }
241
242                 // {true, false, 1, 0}
243                 public static bool ToBoolean(string s)
244                 {
245                         s = s.Trim (XmlChar.WhitespaceChars);
246                         switch(s)
247                         {
248                                 case "1":
249                                         return true;
250                                 case "true":
251                                         return true;
252                                 case "0":
253                                         return false;
254                                 case "false":
255                                         return false;
256                                 default:
257                                         throw new FormatException(s + " is not a valid boolean value");
258                         }
259                 }
260
261                 // LAMESPEC: It has been documented as public, but is marked as internal.
262                 internal static string ToBinHexString (byte [] buffer)
263                 {
264                         StringWriter w = new StringWriter ();
265                         WriteBinHex (buffer, 0, buffer.Length, w);
266                         return w.ToString ();
267                 }
268
269                 internal static void WriteBinHex (byte [] buffer, int index, int count, TextWriter w)
270                 {
271                         if (buffer == null)
272                                 throw new ArgumentNullException ("buffer");
273                         if (index < 0) {
274                                 throw new ArgumentOutOfRangeException (
275 #if !NET_2_1
276                                         "index", index,
277 #endif
278                                         "index must be non negative integer.");
279                         }
280                         if (count < 0) {
281                                 throw new ArgumentOutOfRangeException (
282 #if !NET_2_1
283                                         "count", count,
284 #endif
285                                         "count must be non negative integer.");
286                         }
287                         if (buffer.Length < index + count)
288                                 throw new ArgumentOutOfRangeException ("index and count must be smaller than the length of the buffer.");
289
290                         // Copied from XmlTextWriter.WriteBinHex ()
291                         int end = index + count;
292                         for (int i = index; i < end; i++) {
293                                 int val = buffer [i];
294                                 int high = val >> 4;
295                                 int low = val & 15;
296                                 if (high > 9)
297                                         w.Write ((char) (high + 55));
298                                 else
299                                         w.Write ((char) (high + 0x30));
300                                 if (low > 9)
301                                         w.Write ((char) (low + 55));
302                                 else
303                                         w.Write ((char) (low + 0x30));
304                         }
305                 }
306
307                 public static byte ToByte(string s)
308                 {
309                         return Byte.Parse(s, CultureInfo.InvariantCulture);
310                 }
311
312                 public static char ToChar(string s)
313                 {
314                         return Char.Parse(s);
315                 }
316
317 #if NET_2_0
318                 [Obsolete]
319 #endif
320                 public static DateTime ToDateTime (string s)
321                 {
322                         return ToDateTime (s, datetimeFormats);
323                 }
324                 
325 #if NET_2_0
326                 public static DateTime ToDateTime (string value, XmlDateTimeSerializationMode mode)
327                 {
328                         string modestr = null;
329                         DateTime dt;
330                         switch (mode) {
331                         case XmlDateTimeSerializationMode.Local:
332                                 dt = ToDateTime (value, localDateTimeFormats);
333                                 return dt == DateTime.MinValue || dt == DateTime.MaxValue ? dt : dt.ToLocalTime ();
334                         case XmlDateTimeSerializationMode.RoundtripKind:
335                                 return ToDateTime (value, roundtripDateTimeFormats);
336                         case XmlDateTimeSerializationMode.Utc:
337                                 dt = ToDateTime (value, utcDateTimeFormats);
338                                 return dt == DateTime.MinValue || dt == DateTime.MaxValue ? dt : dt.ToUniversalTime ();
339                         case XmlDateTimeSerializationMode.Unspecified:
340                         default:
341                                 return ToDateTime (value, defaultDateTimeFormats);
342                         }
343                 }
344 #endif
345                 public static DateTime ToDateTime(string s, string format)
346                 {
347                         //DateTimeFormatInfo d = new DateTimeFormatInfo();
348                         //d.FullDateTimePattern = format;
349                         //return DateTime.Parse(s, d);
350                         DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
351                                                DateTimeStyles.AllowTrailingWhite;
352                         return DateTime.ParseExact (s, format, DateTimeFormatInfo.InvariantInfo, style);
353                 }
354
355                 public static DateTime ToDateTime(string s, string[] formats)
356                 {
357                         DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
358                                                DateTimeStyles.AllowTrailingWhite;
359                         return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
360                 }
361                 
362                 public static Decimal ToDecimal(string s)
363                 {
364                         return Decimal.Parse(s, CultureInfo.InvariantCulture);
365                 }
366
367                 public static double ToDouble(string s)
368                 {
369                         if (s == null)
370                                 throw new ArgumentNullException();
371                         if (s == "INF")
372                                 return Double.PositiveInfinity;
373                         if (s == "-INF")
374                                 return Double.NegativeInfinity;
375                         if (s == "NaN")
376                                 return Double.NaN;
377                         return Double.Parse (s, floatStyle, CultureInfo.InvariantCulture);
378                 }
379
380                 public static Guid ToGuid(string s)
381                 {
382                         return new Guid(s);
383                 }
384
385                 public static short ToInt16(string s)
386                 {
387                         return Int16.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
388                 }
389
390                 public static int ToInt32(string s)
391                 {
392                         return Int32.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
393                 }
394
395                 public static long ToInt64(string s)
396                 {
397                         return Int64.Parse (s, NumberStyles.Integer, CultureInfo.InvariantCulture);
398                 }
399
400                 [CLSCompliant (false)]
401                 public static SByte ToSByte(string s)
402                 {
403                         return SByte.Parse(s, CultureInfo.InvariantCulture);
404                 }
405
406                 public static float ToSingle(string s)
407                 {
408                         if (s == null)
409                                 throw new ArgumentNullException();
410                         if (s == "INF")
411                                 return Single.PositiveInfinity;
412                         if (s == "-INF")
413                                 return Single.NegativeInfinity;
414                         if (s == "NaN")
415                                 return Single.NaN;
416                         return Single.Parse(s, floatStyle, CultureInfo.InvariantCulture);
417                 }
418
419                 public static string ToString(Guid value)
420                 {
421                         return value.ToString("D", CultureInfo.InvariantCulture);
422                 }
423
424                 public static string ToString(int value)
425                 {
426                         return value.ToString(CultureInfo.InvariantCulture);
427                 }
428
429                 public static string ToString(short value)
430                 {
431                         return value.ToString(CultureInfo.InvariantCulture);
432                 }
433
434                 public static string ToString(byte value)
435                 {
436                         return value.ToString(CultureInfo.InvariantCulture);
437                 }
438
439                 public static string ToString(long value)
440                 {
441                         return value.ToString(CultureInfo.InvariantCulture);
442                 }
443
444                 public static string ToString(char value)
445                 {
446                         return value.ToString(CultureInfo.InvariantCulture);
447                 }
448
449                 public static string ToString(bool value)
450                 {
451                         if (value) return "true";
452                         return "false";
453                 }
454
455                 [CLSCompliant (false)]
456                 public static string ToString(SByte value)
457                 {
458                         return value.ToString(CultureInfo.InvariantCulture);
459                 }
460
461                 public static string ToString(Decimal value)
462                 {
463                         return value.ToString (CultureInfo.InvariantCulture);
464                 }
465
466                 [CLSCompliant (false)]
467                 public static string ToString(UInt64 value)
468                 {
469                         return value.ToString(CultureInfo.InvariantCulture);
470                 }
471
472                 public static string ToString (TimeSpan value)
473                 {
474                         if (value == TimeSpan.Zero)
475                                 return "PT0S";
476
477                         StringBuilder builder = new StringBuilder ();
478                         if (value.Ticks < 0) {
479                                 builder.Append ('-');
480                                 value = value.Negate ();
481                         }
482                         builder.Append ('P');
483                         if (value.Days > 0)
484                                 builder.Append (value.Days).Append ('D');
485                         if (value.Days > 0 || value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
486                                 builder.Append('T');
487                                 if (value.Hours > 0)
488                                         builder.Append (value.Hours).Append ('H');
489                                 if (value.Minutes > 0) 
490                                         builder.Append (value.Minutes).Append ('M');
491                                 if (value.Seconds > 0 || value.Milliseconds > 0) {
492                                         builder.Append (value.Seconds);
493                                         long ticks = value.Ticks % TimeSpan.TicksPerMillisecond;
494                                         if (ticks > 0)
495                                                 builder.Append ('.').AppendFormat ("{0:0000000}", value.Ticks % TimeSpan.TicksPerSecond);
496                                         else if (value.Milliseconds > 0)
497                                                 builder.Append ('.').AppendFormat ("{0:000}", value.Milliseconds);
498
499                                         builder.Append ('S');
500                                 }
501                         }
502                         return builder.ToString ();
503                 }
504
505                 public static string ToString(double value)
506                 {
507                         if (Double.IsNegativeInfinity(value)) return "-INF";
508                         if (Double.IsPositiveInfinity(value)) return "INF";
509                         if (Double.IsNaN(value)) return "NaN";
510                         return value.ToString(CultureInfo.InvariantCulture);
511                 }
512
513                 public static string ToString(float value)
514                 {
515                         if (Single.IsNegativeInfinity(value)) return "-INF";
516                         if (Single.IsPositiveInfinity(value)) return "INF";
517                         if (Single.IsNaN(value)) return "NaN";
518                         return value.ToString(CultureInfo.InvariantCulture);
519                 }
520
521                 [CLSCompliant (false)]
522                 public static string ToString(UInt32 value)
523                 {
524                         return value.ToString(CultureInfo.InvariantCulture);
525                 }
526
527                 [CLSCompliant (false)]
528                 public static string ToString(UInt16 value)
529                 {
530                         return value.ToString(CultureInfo.InvariantCulture);
531                 }
532
533 #if NET_2_0
534                 [Obsolete]
535 #endif
536                 public static string ToString (DateTime value)
537                 {
538                         return value.ToString ("yyyy-MM-ddTHH:mm:ss.fffffffzzz", CultureInfo.InvariantCulture);
539                 }
540
541 #if NET_2_0
542                 public static string ToString (DateTime value, XmlDateTimeSerializationMode mode)
543                 {
544                         // Unlike usual DateTime formatting, it preserves
545                         // MaxValue/MinValue as is.
546                         string modestr = null;
547                         switch (mode) {
548                         case XmlDateTimeSerializationMode.Local:
549                                 return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToLocalTime ()).ToString (
550                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
551                                         CultureInfo.InvariantCulture);
552                                 break;
553                         case XmlDateTimeSerializationMode.RoundtripKind:
554                                 return value.ToString (
555                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
556                                         CultureInfo.InvariantCulture);
557                                 break;
558                         default:
559                                 return value.ToString (
560                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
561                                         CultureInfo.InvariantCulture);
562                                 break;
563                         case XmlDateTimeSerializationMode.Utc:
564                                 return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToUniversalTime ()).ToString (
565                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",
566                                         CultureInfo.InvariantCulture);
567                                 break;
568                         case XmlDateTimeSerializationMode.Unspecified:
569                                 return value.ToString (
570                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
571                                         CultureInfo.InvariantCulture);
572                                 break;
573                         }
574                 }
575 #endif
576
577                 public static string ToString(DateTime value, string format)
578                 {
579                         return value.ToString(format, CultureInfo.InvariantCulture);
580                 }
581
582                 public static TimeSpan ToTimeSpan(string s)
583                 {
584                         if (s.Length == 0)
585                                 throw new ArgumentException ("Invalid format string for duration schema datatype.");
586
587                         int start = 0;
588                         if (s [0] == '-')
589                                 start = 1;
590                         bool minusValue = (start == 1);
591
592                         if (s [start] != 'P')
593                                 throw new ArgumentException ("Invalid format string for duration schema datatype.");
594                         start++;
595
596                         int parseStep = 0;
597                         int days = 0;
598                         bool isTime = false;
599                         int hours = 0;
600                         int minutes = 0;
601                         int seconds = 0;
602                         long ticks = 0;
603                         int parsedDigits = 0;
604
605                         bool error = false;
606
607                         int i = start;
608                         while (i < s.Length) {
609                                 if (s [i] == 'T') {
610                                         isTime = true;
611                                         parseStep = 4;
612                                         i++;
613                                         start = i;
614                                         continue;
615                                 }
616                                 for (; i < s.Length; i++)
617                                         if (s [i] < '0' || '9' < s [i])
618                                                 break;
619                                 if (parseStep == 7)
620                                         parsedDigits = i - start;
621                                 int value = int.Parse (s.Substring (start, i - start), CultureInfo.InvariantCulture);
622                                 if (parseStep == 7) {
623                                         // adjust to 7 digits so that it makes sense as millisecond digits
624                                         for (; parsedDigits > 7; parsedDigits--)
625                                                 value /= 10;
626                                         for (; parsedDigits < 7; parsedDigits++)
627                                                 value *= 10;
628                                 }
629                                 switch (s [i]) {
630                                 case 'Y':
631                                         days += value * 365;
632                                         if (parseStep > 0)
633                                                 error = true;
634                                         else
635                                                 parseStep = 1;
636                                         break;
637                                 case 'M':
638                                         if (parseStep < 2) {
639                                                 days += 365 * (value / 12) + 30 * (value % 12);
640                                                 parseStep = 2;
641                                         } else if (isTime && parseStep < 6) {
642                                                 minutes = value;
643                                                 parseStep = 6;
644                                         }
645                                         else
646                                                 error = true;
647                                         break;
648                                 case 'D':
649                                         days += value;
650                                         if (parseStep > 2)
651                                                 error = true;
652                                         else
653                                                 parseStep = 3;
654                                         break;
655                                 case 'H':
656                                         hours = value;
657                                         if (!isTime || parseStep > 4)
658                                                 error = true;
659                                         else
660                                                 parseStep = 5;
661                                         break;
662                                 case 'S':
663                                         if (parseStep == 7)
664                                                 ticks = value;
665                                         else
666                                                 seconds = value;
667                                         if (!isTime || parseStep > 7)
668                                                 error = true;
669                                         else
670                                                 parseStep = 8;
671                                         break;
672                                 case '.':
673                                         if (parseStep > 7)
674                                                 error = true;
675                                         seconds = value;
676                                         parseStep = 7;
677                                         break;
678                                 default:
679                                         error = true;
680                                         break;
681                                 }
682                                 if (error)
683                                         break;
684                                 ++i;
685                                 start = i;
686                         }
687                         if (error)
688                                 throw new ArgumentException ("Invalid format string for duration schema datatype.");
689                         TimeSpan ts = new TimeSpan (days, hours, minutes, seconds);
690                         if (minusValue)
691                                 return TimeSpan.FromTicks (- (ts.Ticks + ticks));
692                         else
693                                 return TimeSpan.FromTicks (ts.Ticks + ticks);
694                 }
695
696                 [CLSCompliant (false)]
697                 public static UInt16 ToUInt16(string s)
698                 {
699                         return UInt16.Parse(s, CultureInfo.InvariantCulture);
700                 }
701
702                 [CLSCompliant (false)]
703                 public static UInt32 ToUInt32(string s)
704                 {
705                         return UInt32.Parse(s, CultureInfo.InvariantCulture);
706                 }
707
708                 [CLSCompliant (false)]
709                 public static UInt64 ToUInt64(string s)
710                 {
711                         return UInt64.Parse(s, CultureInfo.InvariantCulture);
712                 }
713
714                 public static string VerifyName (string name)
715                 {
716                         if (name == null || name.Length == 0)
717                                 throw new ArgumentNullException("name");
718
719                         if (!XmlChar.IsName (name))
720                                 throw new XmlException("'" + name + "' is not a valid XML Name");
721                         return name;
722                         
723                 }
724
725                 public static string VerifyNCName (string ncname)
726                 {
727                         if (ncname == null || ncname.Length == 0)
728                                 throw new ArgumentNullException("ncname");
729
730                         if (!XmlChar.IsNCName (ncname))
731                                 throw new XmlException ("'" + ncname + "' is not a valid XML NCName");
732                         return ncname;
733                 }
734
735 #if NET_2_0
736                 public static string VerifyTOKEN (string name)
737 #else
738                 internal static string VerifyTOKEN (string name)
739 #endif
740                 {
741                         if (name == null)
742                                 throw new ArgumentNullException("name");
743
744                         if (name.Length == 0)
745                                 return name;
746
747                         if (XmlChar.IsWhitespace (name [0]) ||
748                                 XmlChar.IsWhitespace (name [name.Length - 1]))
749                                 throw new XmlException ("Whitespace characters (#xA, #xD, #x9, #x20) are not allowed as leading or trailing whitespaces of xs:token.");
750
751                         for (int i = 0; i < name.Length; i++)
752                                 if (XmlChar.IsWhitespace (name [i]) && name [i] != ' ')
753                                 throw new XmlException ("Either #xA, #xD or #x9 are not allowed inside xs:token.");
754
755                         return name;
756                 }
757
758 #if NET_2_0
759                 public static string VerifyNMTOKEN (string name)
760 #else
761                 internal static string VerifyNMTOKEN (string name)
762 #endif
763                 {
764                         if (name == null)
765                                 throw new ArgumentNullException("name");
766
767                         if (!XmlChar.IsNmToken (name))
768                                 throw new XmlException("'" + name + "' is not a valid XML NMTOKEN");
769                         return name;
770                         
771                 }
772
773                 // It is documented as public method, but in fact it is not.
774                 internal static byte [] FromBinHexString (string s)
775                 {
776                         char [] chars = s.ToCharArray ();
777                         byte [] bytes = new byte [chars.Length / 2 + chars.Length % 2];
778                         FromBinHexString (chars, 0, chars.Length, bytes);
779                         return bytes;
780                 }
781
782                 internal static int FromBinHexString (char [] chars, int offset, int charLength, byte [] buffer)
783                 {
784                         int bufIndex = offset;
785                         for (int i = 0; i < charLength - 1; i += 2) {
786                                 buffer [bufIndex] = (chars [i] > '9' ?
787                                                 (byte) (chars [i] - 'A' + 10) :
788                                                 (byte) (chars [i] - '0'));
789                                 buffer [bufIndex] <<= 4;
790                                 buffer [bufIndex] += chars [i + 1] > '9' ?
791                                                 (byte) (chars [i + 1] - 'A' + 10) : 
792                                                 (byte) (chars [i + 1] - '0');
793                                 bufIndex++;
794                         }
795                         if (charLength %2 != 0)
796                                 buffer [bufIndex++] = (byte)
797                                         ((chars [charLength - 1] > '9' ?
798                                                 (byte) (chars [charLength - 1] - 'A' + 10) :
799                                                 (byte) (chars [charLength - 1] - '0'))
800                                         << 4);
801
802                         return bufIndex - offset;
803                 }
804
805 #if NET_2_0 // actually NET_3_5
806
807                 public static DateTimeOffset ToDateTimeOffset (string s)
808                 {
809                         return ToDateTimeOffset (s, datetimeFormats);
810                 }
811
812                 public static DateTimeOffset ToDateTimeOffset (string s, string format)
813                 {
814                         return ToDateTimeOffset (s, format);
815                 }
816
817                 public static DateTimeOffset ToDateTimeOffset (string s, string [] formats)
818                 {
819                         return ToDateTimeOffset (s, formats);
820                 }
821
822                 public static string ToString (DateTimeOffset value)
823                 {
824                         return ToString (value, "yyyy-MM-ddTHH:mm:ss.fffffffzzz");
825                 }
826
827                 public static string ToString (DateTimeOffset value, string format)
828                 {
829                         return value.ToString (format, CultureInfo.InvariantCulture);
830                 }
831 #endif
832         }
833 }