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