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