Update PointConverter.cs
[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                         NumberStyles.AllowLeadingWhite |
49                         NumberStyles.AllowTrailingWhite;
50                 
51                 const NumberStyles integerStyle = NumberStyles.Integer |
52                         NumberStyles.AllowLeadingWhite |
53                         NumberStyles.AllowTrailingWhite;
54
55                 static readonly string [] datetimeFormats = {
56                   // dateTime
57 #if NET_2_0
58                   "yyyy-MM-ddTHH:mm:sszzz",
59                   "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
60                   "yyyy-MM-ddTHH:mm:ssZ",
61                   "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",
62                   "yyyy-MM-ddTHH:mm:ss",
63                   "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
64                   "HH:mm:ss",
65                   "HH:mm:ss.FFFFFFF",
66                   "HH:mm:sszzz",
67                   "HH:mm:ss.FFFFFFFzzz",
68                   "HH:mm:ssZ",
69                   "HH:mm:ss.FFFFFFFZ",
70 #else // it is not required in trunk but should make it easy to backport...
71                   "yyyy-MM-ddTHH:mm:sszzz",
72                   "yyyy-MM-ddTHH:mm:ss.fzzz",
73                   "yyyy-MM-ddTHH:mm:ss.ffzzz",
74                   "yyyy-MM-ddTHH:mm:ss.fffzzz",
75                   "yyyy-MM-ddTHH:mm:ss.ffffzzz",
76                   "yyyy-MM-ddTHH:mm:ss.fffffzzz",
77                   "yyyy-MM-ddTHH:mm:ss.ffffffzzz",
78                   "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
79                   "yyyy-MM-ddTHH:mm:ssZ",
80                   "yyyy-MM-ddTHH:mm:ss.fZ",
81                   "yyyy-MM-ddTHH:mm:ss.ffZ",
82                   "yyyy-MM-ddTHH:mm:ss.fffZ",
83                   "yyyy-MM-ddTHH:mm:ss.ffffZ",
84                   "yyyy-MM-ddTHH:mm:ss.fffffZ",
85                   "yyyy-MM-ddTHH:mm:ss.ffffffZ",
86                   "yyyy-MM-ddTHH:mm:ss.fffffffZ",
87                   "yyyy-MM-ddTHH:mm:ss",
88                   "yyyy-MM-ddTHH:mm:ss.f",
89                   "yyyy-MM-ddTHH:mm:ss.ff",
90                   "yyyy-MM-ddTHH:mm:ss.fff",
91                   "yyyy-MM-ddTHH:mm:ss.ffff",
92                   "yyyy-MM-ddTHH:mm:ss.fffff",
93                   "yyyy-MM-ddTHH:mm:ss.ffffff",
94                   "yyyy-MM-ddTHH:mm:ss.fffffff",
95                   // time
96                   "HH:mm:ss",
97                   "HH:mm:ss.f",
98                   "HH:mm:ss.ff",
99                   "HH:mm:ss.fff",
100                   "HH:mm:ss.ffff",
101                   "HH:mm:ss.fffff",
102                   "HH:mm:ss.ffffff",
103                   "HH:mm:ss.fffffff",
104                   "HH:mm:sszzz",
105                   "HH:mm:ss.fzzz",
106                   "HH:mm:ss.ffzzz",
107                   "HH:mm:ss.fffzzz",
108                   "HH:mm:ss.ffffzzz",
109                   "HH:mm:ss.fffffzzz",
110                   "HH:mm:ss.ffffffzzz",
111                   "HH:mm:ss.fffffffzzz",
112                   "HH:mm:ssZ",
113                   "HH:mm:ss.fZ",
114                   "HH:mm:ss.ffZ",
115                   "HH:mm:ss.fffZ",
116                   "HH:mm:ss.ffffZ",
117                   "HH:mm:ss.fffffZ",
118                   "HH:mm:ss.ffffffZ",
119                   "HH:mm:ss.fffffffZ",
120 #endif
121                   // date
122                   "yyyy-MM-dd",
123                   "yyyy-MM-ddzzz",
124                   "yyyy-MM-ddZ",
125                   // gYearMonth
126                   "yyyy-MM",
127                   "yyyy-MMzzz",
128                   "yyyy-MMZ",
129                   // gYear
130                   "yyyy",
131                   "yyyyzzz",
132                   "yyyyZ",
133                   // gMonthDay
134                   "--MM-dd",
135                   "--MM-ddzzz",
136                   "--MM-ddZ",
137                   // gDay
138                   "---dd",
139                   "---ddzzz",
140                   "---ddZ",
141                 };
142
143 #if NET_2_0
144                 static readonly string [] defaultDateTimeFormats = new string [] {
145                         "yyyy-MM-ddTHH:mm:ss", // dateTime(1)
146                         "yyyy-MM-ddTHH:mm:ss.FFFFFFF", // dateTime(2)
147                         "yyyy-MM-dd", // date
148                         "HH:mm:ss", // time
149                         "yyyy-MM", // gYearMonth
150                         "yyyy", // gYear
151                         "--MM-dd", // gMonthDay
152                         "---dd", // gDay
153                         };
154
155                 static readonly string [] roundtripDateTimeFormats;
156                 static readonly string [] localDateTimeFormats;
157                 static readonly string [] utcDateTimeFormats;
158                 static readonly string [] unspecifiedDateTimeFormats;
159
160                 static XmlConvert ()
161                 {
162                         int l = defaultDateTimeFormats.Length;
163                         roundtripDateTimeFormats = new string [l * 2];
164                         localDateTimeFormats = new string [l * 2];
165                         utcDateTimeFormats = new string [l * 3];
166                         unspecifiedDateTimeFormats = new string [l * 5];
167                         for (int i = 0; i < l; i++) {
168                                 string s = defaultDateTimeFormats [i];
169                                 var z = s + 'Z';
170                                 localDateTimeFormats [i * 2] = s + (s [s.Length - 1] == 's' || s [s.Length - 1] == 'F' ? "zzz" : String.Empty);
171                                 localDateTimeFormats [i * 2 + 1] = z;
172                                 roundtripDateTimeFormats [i * 2] = s + 'K';
173                                 roundtripDateTimeFormats [i * 2 + 1] = z;
174                                 utcDateTimeFormats [i * 3] = s;
175                                 utcDateTimeFormats [i * 3 + 1] = z;
176                                 utcDateTimeFormats [i * 3 + 2] = s + "zzz";
177                                 unspecifiedDateTimeFormats [i * 5] = s;
178                                 unspecifiedDateTimeFormats [i * 5 + 1] = z;
179                                 unspecifiedDateTimeFormats [i * 5 + 2] = localDateTimeFormats [i];
180                                 unspecifiedDateTimeFormats [i * 5 + 3] = roundtripDateTimeFormats [i];
181                                 unspecifiedDateTimeFormats [i * 5 + 4] = utcDateTimeFormats [i];
182                         }
183                 }
184 #endif
185                 static DateTimeStyles _defaultStyle = DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite;
186                 
187                 public XmlConvert()
188                 {}
189
190                 private static string TryDecoding (string s)
191                 {
192                         if (s == null || s.Length < 6)
193                                 return s;
194
195                         char c = '\uFFFF';
196                         try {
197                                 c = (char) Int32.Parse (s.Substring (1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
198                         } catch {
199                                 return s [0] + DecodeName (s.Substring (1));
200                         }
201                         
202                         if (s.Length == 6)
203                                 return c.ToString ();
204                         return c + DecodeName (s.Substring (6));
205                 }
206                 
207                 public static string DecodeName (string name)
208                 {
209                         if (name == null || name.Length == 0)
210                                 return name;
211
212                         int pos = name.IndexOf ('_');
213                         if (pos == -1 || pos + 6 >= name.Length)
214                                 return name;
215
216                         if ((name [pos + 1] != 'X' && name [pos + 1] != 'x') || name [pos + 6] != '_')
217                                 return name [0] + DecodeName (name.Substring (1));
218
219                         return name.Substring (0, pos) + TryDecoding (name.Substring (pos + 1));
220                 }
221
222                 public static string EncodeLocalName (string name)
223                 {
224                         if (name == null)
225                                 return name;
226
227                         string encoded = EncodeName (name);
228                         int pos = encoded.IndexOf (':');
229                         if (pos == -1)
230                                 return encoded;
231                         return encoded.Replace (":", encodedColon);
232                 }
233
234                 internal static bool IsInvalid (char c, bool firstOnlyLetter)
235                 {
236                         if (c == ':') // Special case. allowed in EncodeName, but encoded in EncodeLocalName
237                                 return false;
238                         
239                         if (firstOnlyLetter)
240                                 return !XmlChar.IsFirstNameChar (c);
241                         else
242                                 return !XmlChar.IsNameChar (c);
243                 }
244
245                 private static string EncodeName (string name, bool nmtoken)
246                 {
247                         if (name == null || name.Length == 0)
248                                 return name;
249
250                         StringBuilder sb = new StringBuilder ();
251                         int length = name.Length;
252                         for (int i = 0; i < length; i++) {
253                                 char c = name [i];
254                                 if (IsInvalid (c, i == 0 && !nmtoken))
255                                         sb.AppendFormat ("_x{0:X4}_", (int) c);
256                                 else if (c == '_' && i + 6 < length && name [i+1] == 'x' && name [i + 6] == '_')
257                                         sb.Append ("_x005F_");
258                                 else
259                                         sb.Append (c);
260                         }
261                         return sb.ToString ();
262                 }
263
264                 public static string EncodeName (string name)
265                 {
266                         return EncodeName (name, false);
267                 }
268                 
269                 public static string EncodeNmToken (string name)
270                 {
271                         if (name == String.Empty)
272                                 throw new XmlException ("Invalid NmToken: ''");
273                         return EncodeName (name, true);
274                 }
275
276                 // {true, false, 1, 0}
277                 public static bool ToBoolean(string s)
278                 {
279                         s = s.Trim (XmlChar.WhitespaceChars);
280                         switch(s)
281                         {
282                                 case "1":
283                                         return true;
284                                 case "true":
285                                         return true;
286                                 case "0":
287                                         return false;
288                                 case "false":
289                                         return false;
290                                 default:
291                                         throw new FormatException(s + " is not a valid boolean value");
292                         }
293                 }
294
295                 // LAMESPEC: It has been documented as public, but is marked as internal.
296                 internal static string ToBinHexString (byte [] buffer)
297                 {
298                         StringWriter w = new StringWriter ();
299                         WriteBinHex (buffer, 0, buffer.Length, w);
300                         return w.ToString ();
301                 }
302
303                 internal static void WriteBinHex (byte [] buffer, int index, int count, TextWriter w)
304                 {
305                         if (buffer == null)
306                                 throw new ArgumentNullException ("buffer");
307                         if (index < 0) {
308                                 throw new ArgumentOutOfRangeException (
309 #if !NET_2_1
310                                         "index", index,
311 #endif
312                                         "index must be non negative integer.");
313                         }
314                         if (count < 0) {
315                                 throw new ArgumentOutOfRangeException (
316 #if !NET_2_1
317                                         "count", count,
318 #endif
319                                         "count must be non negative integer.");
320                         }
321                         if (buffer.Length < index + count)
322                                 throw new ArgumentOutOfRangeException ("index and count must be smaller than the length of the buffer.");
323
324                         // Copied from XmlTextWriter.WriteBinHex ()
325                         int end = index + count;
326                         for (int i = index; i < end; i++) {
327                                 int val = buffer [i];
328                                 int high = val >> 4;
329                                 int low = val & 15;
330                                 if (high > 9)
331                                         w.Write ((char) (high + 55));
332                                 else
333                                         w.Write ((char) (high + 0x30));
334                                 if (low > 9)
335                                         w.Write ((char) (low + 55));
336                                 else
337                                         w.Write ((char) (low + 0x30));
338                         }
339                 }
340
341                 public static byte ToByte(string s)
342                 {
343                         return Byte.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
344                 }
345
346                 public static char ToChar(string s)
347                 {
348 #if !NET_2_1
349                         return Char.Parse(s);
350 #else
351                         if (s == null)
352                                 throw new ArgumentNullException ("s");
353
354                         if (s.Length != 1)
355                                 throw new FormatException ("String contain more than one char");
356
357                         return s [0];
358 #endif
359                 }
360
361 #if NET_2_0
362                 [Obsolete]
363 #endif
364                 public static DateTime ToDateTime (string s)
365                 {
366                         return ToDateTime (s, datetimeFormats);
367                 }
368                 
369 #if NET_2_0
370                 public static DateTime ToDateTime (string s, XmlDateTimeSerializationMode dateTimeOption)
371                 {
372                         DateTime dt;
373                         switch (dateTimeOption) {
374                         case XmlDateTimeSerializationMode.Local:
375                                 dt = ToDateTime (s, localDateTimeFormats);
376                                 return new DateTime (dt.Ticks, DateTimeKind.Local);
377                         case XmlDateTimeSerializationMode.RoundtripKind:
378                                 return ToDateTime (s, roundtripDateTimeFormats, _defaultStyle | DateTimeStyles.RoundtripKind);
379                         case XmlDateTimeSerializationMode.Utc:
380                                 dt = ToDateTime (s, utcDateTimeFormats);
381                                 return new DateTime (dt.Ticks, DateTimeKind.Utc);
382                         case XmlDateTimeSerializationMode.Unspecified:
383                                 return ToDateTime (s, unspecifiedDateTimeFormats);
384                         default:
385                                 return ToDateTime (s, defaultDateTimeFormats);
386                         }
387                 }
388 #endif
389                 public static DateTime ToDateTime(string s, string format)
390                 {
391                         //DateTimeFormatInfo d = new DateTimeFormatInfo();
392                         //d.FullDateTimePattern = format;
393                         //return DateTime.Parse(s, d);
394                         DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
395                                                DateTimeStyles.AllowTrailingWhite;                       
396                         return DateTime.ParseExact (s, format, DateTimeFormatInfo.InvariantInfo, style);
397                 }
398
399                 public static DateTime ToDateTime(string s, string[] formats)
400                 {
401                         return ToDateTime (s, formats, _defaultStyle);                  
402                 }
403
404                 private static DateTime ToDateTime (string s, string [] formats, DateTimeStyles style) 
405                 {
406                         try {
407                                 return DateTime.ParseExact (s, formats, DateTimeFormatInfo.InvariantInfo, style);
408                         } catch (ArgumentOutOfRangeException) {
409                                 return DateTime.MinValue;
410                         }
411                 }
412                 
413                 public static Decimal ToDecimal(string s)
414                 {
415                         return Decimal.Parse(s, CultureInfo.InvariantCulture);
416                 }
417
418                 public static double ToDouble(string s)
419                 {
420                         if (s == null)
421                                 throw new ArgumentNullException();
422
423                         float f = TryParseStringFloatConstants (s);
424                         if (f != 0)
425                                 return f;
426
427                         return Double.Parse (s, floatStyle, CultureInfo.InvariantCulture);
428                 }
429
430                 static float TryParseStringFloatConstants (string s)
431                 {
432                         int sidx = 0;
433                         while (sidx < s.Length && Char.IsWhiteSpace (s [sidx]))
434                                 sidx++;
435                         if (sidx == s.Length)
436                                 throw new FormatException ();
437                         int sEndPos = s.Length - 1;
438                         while (Char.IsWhiteSpace (s [sEndPos]))
439                                 sEndPos--;
440
441                         if (TryParseStringConstant ("NaN", s, sidx, sEndPos))
442                                 return Single.NaN;
443                         if (TryParseStringConstant ("INF", s, sidx, sEndPos))
444                                 return Single.PositiveInfinity;
445                         if (TryParseStringConstant ("-INF", s, sidx, sEndPos))
446                                 return Single.NegativeInfinity;
447                         // Handle these here because Single.Parse("Infinity") is invalid while XmlConvert.ToSingle("Infinity") is valid.
448                         if (TryParseStringConstant ("Infinity", s, sidx, sEndPos))
449                                 return Single.PositiveInfinity;
450                         if (TryParseStringConstant ("-Infinity", s, sidx, sEndPos))
451                                 return Single.NegativeInfinity;
452                         return 0;
453                 }
454
455                 static bool TryParseStringConstant (string format, string s, int start, int end)
456                 {
457                         return end - start + 1 == format.Length && String.CompareOrdinal (format, 0, s, start, format.Length) == 0;
458                 }
459
460                 public static Guid ToGuid (string s)
461                 {
462                         try {
463                                 return new Guid(s);
464                         } catch (FormatException ex) {
465                                 throw new FormatException (String.Format ("Invalid Guid input '{0}'", ex.InnerException));
466                         }
467                 }
468
469                 public static short ToInt16(string s)
470                 {
471                         return Int16.Parse (s, integerStyle, CultureInfo.InvariantCulture);
472                 }
473
474                 public static int ToInt32(string s)
475                 {
476                         return Int32.Parse (s, integerStyle, CultureInfo.InvariantCulture);
477                 }
478
479                 public static long ToInt64(string s)
480                 {
481                         return Int64.Parse (s, integerStyle, CultureInfo.InvariantCulture);
482                 }
483
484                 [CLSCompliant (false)]
485                 public static SByte ToSByte(string s)
486                 {
487                         return SByte.Parse(s, integerStyle, CultureInfo.InvariantCulture);
488                 }
489
490                 public static float ToSingle(string s)
491                 {
492                         if (s == null)
493                                 throw new ArgumentNullException();
494
495                         float f = TryParseStringFloatConstants (s);
496                         if (f != 0)
497                                 return f;
498
499                         return Single.Parse(s, floatStyle, CultureInfo.InvariantCulture);
500                 }
501
502                 public static string ToString(Guid value)
503                 {
504                         return value.ToString("D", CultureInfo.InvariantCulture);
505                 }
506
507                 public static string ToString(int value)
508                 {
509                         return value.ToString(CultureInfo.InvariantCulture);
510                 }
511
512                 public static string ToString(short value)
513                 {
514                         return value.ToString(CultureInfo.InvariantCulture);
515                 }
516
517                 public static string ToString(byte value)
518                 {
519                         return value.ToString(CultureInfo.InvariantCulture);
520                 }
521
522                 public static string ToString(long value)
523                 {
524                         return value.ToString(CultureInfo.InvariantCulture);
525                 }
526
527                 public static string ToString(char value)
528                 {
529                         return value.ToString(CultureInfo.InvariantCulture);
530                 }
531
532                 public static string ToString(bool value)
533                 {
534                         if (value) return "true";
535                         return "false";
536                 }
537
538                 [CLSCompliant (false)]
539                 public static string ToString(SByte value)
540                 {
541                         return value.ToString(CultureInfo.InvariantCulture);
542                 }
543
544                 public static string ToString(Decimal value)
545                 {
546                         return value.ToString (CultureInfo.InvariantCulture);
547                 }
548
549                 [CLSCompliant (false)]
550                 public static string ToString(UInt64 value)
551                 {
552                         return value.ToString(CultureInfo.InvariantCulture);
553                 }
554
555                 public static string ToString (TimeSpan value)
556                 {
557                         if (value == TimeSpan.Zero)
558                                 return "PT0S";
559
560                         StringBuilder builder = new StringBuilder ();
561                         if (value.Ticks < 0) {
562                                 if (value == TimeSpan.MinValue)
563                                         return "-P10675199DT2H48M5.4775808S";  // There's one fewer tick on the positive side, so we cannot Negate this value; just hard-code it
564                                 builder.Append ('-');
565                                 value = value.Negate ();
566                         }
567                         builder.Append ('P');
568                         if (value.Days > 0)
569                                 builder.Append (value.Days).Append ('D');
570                         long ticks = value.Ticks % TimeSpan.TicksPerMillisecond;
571                         if (value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0 || ticks > 0) {
572                                 builder.Append('T');
573                                 if (value.Hours > 0)
574                                         builder.Append (value.Hours).Append ('H');
575                                 if (value.Minutes > 0) 
576                                         builder.Append (value.Minutes).Append ('M');
577                                 if (value.Seconds > 0 || value.Milliseconds > 0 || ticks > 0) {
578                                         builder.Append (value.Seconds);
579                                         bool trimZero = true;
580                                         if (ticks > 0)
581                                                 builder.Append ('.').AppendFormat ("{0:0000000}", value.Ticks % TimeSpan.TicksPerSecond);
582                                         else if (value.Milliseconds > 0)
583                                                 builder.Append ('.').AppendFormat ("{0:000}", value.Milliseconds);
584                                         else
585                                                 trimZero = false;
586                                         if (trimZero)
587                                                 while (builder [builder.Length - 1] == '0')
588                                                         builder.Remove (builder.Length - 1, 1);
589
590                                         builder.Append ('S');
591                                 }
592                         }
593                         return builder.ToString ();
594                 }
595
596                 public static string ToString(double value)
597                 {
598                         if (Double.IsNegativeInfinity(value)) return "-INF";
599                         if (Double.IsPositiveInfinity(value)) return "INF";
600                         if (Double.IsNaN(value)) return "NaN";
601                         return value.ToString("R", CultureInfo.InvariantCulture);
602                 }
603
604                 public static string ToString(float value)
605                 {
606                         if (Single.IsNegativeInfinity(value)) return "-INF";
607                         if (Single.IsPositiveInfinity(value)) return "INF";
608                         if (Single.IsNaN(value)) return "NaN";
609                         return value.ToString("R", CultureInfo.InvariantCulture);
610                 }
611
612                 [CLSCompliant (false)]
613                 public static string ToString(UInt32 value)
614                 {
615                         return value.ToString(CultureInfo.InvariantCulture);
616                 }
617
618                 [CLSCompliant (false)]
619                 public static string ToString(UInt16 value)
620                 {
621                         return value.ToString(CultureInfo.InvariantCulture);
622                 }
623
624 #if NET_2_0
625                 [Obsolete]
626 #endif
627                 public static string ToString (DateTime value)
628                 {
629                         return value.ToString ("yyyy-MM-ddTHH:mm:ss.fffffffzzz", CultureInfo.InvariantCulture);
630                 }
631
632 #if NET_2_0
633                 public static string ToString (DateTime value, XmlDateTimeSerializationMode dateTimeOption)
634                 {
635                         // Unlike usual DateTime formatting, it preserves
636                         // MaxValue/MinValue as is.
637                         switch (dateTimeOption) {
638                         case XmlDateTimeSerializationMode.Local:
639                                 return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToLocalTime ()).ToString (
640                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
641                                         CultureInfo.InvariantCulture);
642                         case XmlDateTimeSerializationMode.RoundtripKind:
643                                 return value.ToString (
644                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
645                                         CultureInfo.InvariantCulture);
646                         default:
647                                 return value.ToString (
648                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz",
649                                         CultureInfo.InvariantCulture);
650                         case XmlDateTimeSerializationMode.Utc:
651                                 return (value == DateTime.MinValue ? DateTime.MinValue : value == DateTime.MaxValue ? value : value.ToUniversalTime ()).ToString (
652                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFFZ",
653                                         CultureInfo.InvariantCulture);
654                         case XmlDateTimeSerializationMode.Unspecified:
655                                 return value.ToString (
656                                         "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
657                                         CultureInfo.InvariantCulture);
658                         }
659                 }
660 #endif
661
662                 public static string ToString(DateTime value, string format)
663                 {
664                         return value.ToString(format, CultureInfo.InvariantCulture);
665                 }
666
667                 public static TimeSpan ToTimeSpan(string s)
668                 {
669                         s = s.Trim (XmlChar.WhitespaceChars);
670                         if (s.Length == 0)
671                                 throw new FormatException ("Invalid format string for duration schema datatype.");
672
673                         int start = 0;
674                         if (s [0] == '-')
675                                 start = 1;
676                         bool minusValue = (start == 1);
677
678                         if (s [start] != 'P')
679                                 throw new FormatException ("Invalid format string for duration schema datatype.");
680                         start++;
681
682                         int parseStep = 0;
683                         int days = 0;
684                         bool isTime = false;
685                         int hours = 0;
686                         int minutes = 0;
687                         int seconds = 0;
688                         long ticks = 0;
689                         int parsedDigits = 0;
690
691                         bool error = false;
692
693                         int i = start;
694                         while (i < s.Length) {
695                                 if (s [i] == 'T') {
696                                         isTime = true;
697                                         parseStep = 4;
698                                         i++;
699                                         start = i;
700                                         continue;
701                                 }
702                                 for (; i < s.Length; i++)
703                                         if (s [i] < '0' || '9' < s [i])
704                                                 break;
705                                 if (parseStep == 7)
706                                         parsedDigits = i - start;
707                                 int value = int.Parse (s.Substring (start, i - start), CultureInfo.InvariantCulture);
708                                 if (parseStep == 7) {
709                                         // adjust to 7 digits so that it makes sense as millisecond digits
710                                         for (; parsedDigits > 7; parsedDigits--)
711                                                 value /= 10;
712                                         for (; parsedDigits < 7; parsedDigits++)
713                                                 value *= 10;
714                                 }
715                                 switch (s [i]) {
716                                 case 'Y':
717                                         days += value * 365;
718                                         if (parseStep > 0)
719                                                 error = true;
720                                         else
721                                                 parseStep = 1;
722                                         break;
723                                 case 'M':
724                                         if (parseStep < 2) {
725                                                 days += 365 * (value / 12) + 30 * (value % 12);
726                                                 parseStep = 2;
727                                         } else if (isTime && parseStep < 6) {
728                                                 minutes = value;
729                                                 parseStep = 6;
730                                         }
731                                         else
732                                                 error = true;
733                                         break;
734                                 case 'D':
735                                         days += value;
736                                         if (parseStep > 2)
737                                                 error = true;
738                                         else
739                                                 parseStep = 3;
740                                         break;
741                                 case 'H':
742                                         hours = value;
743                                         if (!isTime || parseStep > 4)
744                                                 error = true;
745                                         else
746                                                 parseStep = 5;
747                                         break;
748                                 case 'S':
749                                         if (parseStep == 7)
750                                                 ticks = value;
751                                         else
752                                                 seconds = value;
753                                         if (!isTime || parseStep > 7)
754                                                 error = true;
755                                         else
756                                                 parseStep = 8;
757                                         break;
758                                 case '.':
759                                         if (parseStep > 7)
760                                                 error = true;
761                                         seconds = value;
762                                         parseStep = 7;
763                                         break;
764                                 default:
765                                         error = true;
766                                         break;
767                                 }
768                                 if (error)
769                                         break;
770                                 ++i;
771                                 start = i;
772                         }
773                         if (error)
774                                 throw new FormatException ("Invalid format string for duration schema datatype.");
775                         TimeSpan ts = new TimeSpan (days, hours, minutes, seconds);
776                         if (minusValue)
777                                 return TimeSpan.FromTicks (- (ts.Ticks + ticks));
778                         else
779                                 return TimeSpan.FromTicks (ts.Ticks + ticks);
780                 }
781
782                 [CLSCompliant (false)]
783                 public static UInt16 ToUInt16(string s)
784                 {
785                         return UInt16.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
786                 }
787
788                 [CLSCompliant (false)]
789                 public static UInt32 ToUInt32(string s)
790                 {
791                         return UInt32.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
792                 }
793
794                 [CLSCompliant (false)]
795                 public static UInt64 ToUInt64(string s)
796                 {
797                         return UInt64.Parse(s, NumberStyles.Integer, CultureInfo.InvariantCulture);
798                 }
799
800                 public static string VerifyName (string name)
801                 {
802                         if (name == null || name.Length == 0)
803                                 throw new ArgumentNullException("name");
804
805                         if (!XmlChar.IsName (name))
806                                 throw new XmlException("'" + name + "' is not a valid XML Name");
807                         return name;
808                         
809                 }
810
811                 public static string VerifyNCName (string name)
812                 {
813                         if (name == null || name.Length == 0)
814                                 throw new ArgumentNullException("name");
815
816                         if (!XmlChar.IsNCName (name))
817                                 throw new XmlException ("'" + name + "' is not a valid XML NCName");
818                         return name;
819                 }
820
821                 public static string VerifyTOKEN (string token)
822                 {
823                         if (token == null)
824                                 throw new ArgumentNullException("token");
825
826                         if (token.Length == 0)
827                                 return token;
828
829                         if (XmlChar.IsWhitespace (token [0]) ||
830                                 XmlChar.IsWhitespace (token [token.Length - 1]))
831                                 throw new XmlException ("Whitespace characters (#xA, #xD, #x9, #x20) are not allowed as leading or trailing whitespaces of xs:token.");
832
833                         for (int i = 0; i < token.Length; i++)
834                                 if (XmlChar.IsWhitespace (token [i]) && token [i] != ' ')
835                                         throw new XmlException ("Either #xA, #xD or #x9 are not allowed inside xs:token.");
836
837                         return token;
838                 }
839
840 #if NET_2_0
841                 public static string VerifyNMTOKEN (string name)
842 #else
843                 internal static string VerifyNMTOKEN (string name)
844 #endif
845                 {
846                         if (name == null)
847                                 throw new ArgumentNullException("name");
848
849                         if (!XmlChar.IsNmToken (name))
850                                 throw new XmlException("'" + name + "' is not a valid XML NMTOKEN");
851                         return name;
852                         
853                 }
854
855                 // It is documented as public method, but in fact it is not.
856                 internal static byte [] FromBinHexString (string s)
857                 {
858                         char [] chars = s.ToCharArray ();
859                         byte [] bytes = new byte [chars.Length / 2 + chars.Length % 2];
860                         FromBinHexString (chars, 0, chars.Length, bytes);
861                         return bytes;
862                 }
863
864                 internal static int FromBinHexString (char [] chars, int offset, int charLength, byte [] buffer)
865                 {
866                         int bufIndex = offset;
867                         for (int i = 0; i < charLength - 1; i += 2) {
868                                 buffer [bufIndex] = (chars [i] > '9' ?
869                                                 (byte) (chars [i] - 'A' + 10) :
870                                                 (byte) (chars [i] - '0'));
871                                 buffer [bufIndex] <<= 4;
872                                 buffer [bufIndex] += chars [i + 1] > '9' ?
873                                                 (byte) (chars [i + 1] - 'A' + 10) : 
874                                                 (byte) (chars [i + 1] - '0');
875                                 bufIndex++;
876                         }
877                         if (charLength %2 != 0)
878                                 buffer [bufIndex++] = (byte)
879                                         ((chars [charLength - 1] > '9' ?
880                                                 (byte) (chars [charLength - 1] - 'A' + 10) :
881                                                 (byte) (chars [charLength - 1] - '0'))
882                                         << 4);
883
884                         return bufIndex - offset;
885                 }
886
887 #if NET_2_0 // actually NET_3_5
888 #if !TARGET_JVM
889
890                 public static DateTimeOffset ToDateTimeOffset (string s)
891                 {
892                         return ToDateTimeOffset (s, datetimeFormats);
893                 }
894
895                 public static DateTimeOffset ToDateTimeOffset (string s, string format)
896                 {
897                         return DateTimeOffset.ParseExact (s, format, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
898                 }
899
900                 public static DateTimeOffset ToDateTimeOffset (string s, string [] formats)
901                 {
902                         DateTimeStyles style = DateTimeStyles.AllowLeadingWhite |
903                                                DateTimeStyles.AllowTrailingWhite |
904                                                DateTimeStyles.AssumeUniversal;
905                         return DateTimeOffset.ParseExact (s, formats, CultureInfo.InvariantCulture, style);
906                 }
907
908                 public static string ToString (DateTimeOffset value)
909                 {
910                         return ToString (value, "yyyy-MM-ddTHH:mm:ss.FFFFFFFzzz");
911                 }
912
913                 public static string ToString (DateTimeOffset value, string format)
914                 {
915                         return value.ToString (format, CultureInfo.InvariantCulture);
916                 }
917 #endif
918
919                 // it is used only from 2.1 System.Xml.Serialization.dll from
920                 // MS Silverlight SDK. We don't use it so far.
921                 internal static Uri ToUri (string s)
922                 {
923                         return new Uri (s, UriKind.RelativeOrAbsolute);
924                 }
925
926 #endif
927
928 #if NET_4_0
929                 public static bool IsNCNameChar (char ch)
930                 {
931                         throw new NotImplementedException ();
932                 }
933
934                 public static bool IsPublicIdChar (char ch)
935                 {
936                         throw new NotImplementedException ();
937                 }
938
939                 public static bool IsStartNCNameChar (char ch)
940                 {
941                         throw new NotImplementedException ();
942                 }
943
944                 public static bool IsWhitespaceChar (char ch)
945                 {
946                         throw new NotImplementedException ();
947                 }
948
949                 public static bool IsXmlChar (char ch)
950                 {
951                         throw new NotImplementedException ();
952                 }
953
954                 public static bool IsXmlSurrogatePair (char lowChar, char highChar)
955                 {
956                         throw new NotImplementedException ();
957                 }
958                 
959                 public static string VerifyPublicId (string publicId)
960                 {
961                         throw new NotImplementedException ();
962                 }
963
964                 public static string VerifyWhitespace (string content)
965                 {
966                         throw new NotImplementedException ();
967                 }
968
969                 public static string VerifyXmlChars (string content)
970                 {
971                         throw new NotImplementedException ();
972                 }
973 #endif
974         }
975 }