Switch to compiler-tester
[mono.git] / mcs / class / System.XML / System.Xml / XmlConvert.cs
index b28d42eb6a66a0b9edb29c130f34704cc813a02d..1c59e3e4b1f21d385de7884dc7aec396988675e4 100755 (executable)
@@ -5,11 +5,33 @@
 //      Dwivedi, Ajay kumar (Adwiv@Yahoo.com)
 //     Gonzalo Paniagua Javier (gonzalo@ximian.com)
 //      Alan Tam Siu Lung (Tam@SiuLung.com)
-//     Atsushi Enomoto (ginga@kit.h-ho.ne.jp)
+//     Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
 //
 // (C) 2002 Ximian, Inc (http://www.ximian.com)
 //
+
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
 using System;
+using System.IO;
 using System.Text;
 using System.Globalization;
 using System.Xml.Schema;
@@ -18,86 +40,85 @@ namespace System.Xml {
 
        public class XmlConvert {
 
-               static string encodedColon;
-               static string [] datetimeFormats;
-
-               static XmlConvert ()
-               {
-                       encodedColon = "_x003A_";
-                       datetimeFormats = new string[] {
-                         // dateTime
-                         "yyyy-MM-ddTHH:mm:ss",
-                         "yyyy-MM-ddTHH:mm:ss.f",
-                         "yyyy-MM-ddTHH:mm:ss.ff",
-                         "yyyy-MM-ddTHH:mm:ss.fff",
-                         "yyyy-MM-ddTHH:mm:ss.ffff",
-                         "yyyy-MM-ddTHH:mm:ss.fffff",
-                         "yyyy-MM-ddTHH:mm:ss.ffffff",
-                         "yyyy-MM-ddTHH:mm:ss.fffffff",
-                         "yyyy-MM-ddTHH:mm:sszzz",
-                         "yyyy-MM-ddTHH:mm:ss.fzzz",
-                         "yyyy-MM-ddTHH:mm:ss.ffzzz",
-                         "yyyy-MM-ddTHH:mm:ss.fffzzz",
-                         "yyyy-MM-ddTHH:mm:ss.ffffzzz",
-                         "yyyy-MM-ddTHH:mm:ss.fffffzzz",
-                         "yyyy-MM-ddTHH:mm:ss.ffffffzzz",
-                         "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
-                         "yyyy-MM-ddTHH:mm:ssZ",
-                         "yyyy-MM-ddTHH:mm:ss.fZ",
-                         "yyyy-MM-ddTHH:mm:ss.ffZ",
-                         "yyyy-MM-ddTHH:mm:ss.fffZ",
-                         "yyyy-MM-ddTHH:mm:ss.ffffZ",
-                         "yyyy-MM-ddTHH:mm:ss.fffffZ",
-                         "yyyy-MM-ddTHH:mm:ss.ffffffZ",
-                         "yyyy-MM-ddTHH:mm:ss.fffffffZ",
-                         // time
-                         "HH:mm:ss",
-                         "HH:mm:ss.f",
-                         "HH:mm:ss.ff",
-                         "HH:mm:ss.fff",
-                         "HH:mm:ss.ffff",
-                         "HH:mm:ss.fffff",
-                         "HH:mm:ss.ffffff",
-                         "HH:mm:ss.fffffff",
-                         "HH:mm:sszzz",
-                         "HH:mm:ss.fzzz",
-                         "HH:mm:ss.ffzzz",
-                         "HH:mm:ss.fffzzz",
-                         "HH:mm:ss.ffffzzz",
-                         "HH:mm:ss.fffffzzz",
-                         "HH:mm:ss.ffffffzzz",
-                         "HH:mm:ss.fffffffzzz",
-                         "HH:mm:ssZ",
-                         "HH:mm:ss.fZ",
-                         "HH:mm:ss.ffZ",
-                         "HH:mm:ss.fffZ",
-                         "HH:mm:ss.ffffZ",
-                         "HH:mm:ss.fffffZ",
-                         "HH:mm:ss.ffffffZ",
-                         "HH:mm:ss.fffffffZ",
-                         // date
-                         "yyyy-MM-dd",
-                         "yyyy-MM-ddzzz",
-                         "yyyy-MM-ddZ",
-                         // gYearMonth
-                         "yyyy-MM",
-                         "yyyy-MMzzz",
-                         "yyyy-MMZ",
-                         // gYear
-                         "yyyy",
-                         "yyyyzzz",
-                         "yyyyZ",
-                         // gMonthDay
-                         "--MM-dd",
-                         "--MM-ddzzz",
-                         "--MM-ddZ",
-                         // gDay
-                         "---dd",
-                         "---ddzzz",
-                         "---ddZ",
-                       };
-               }
-
+               const string encodedColon = "_x003A_";
+               const NumberStyles floatStyle = NumberStyles.AllowCurrencySymbol |
+                       NumberStyles.AllowExponent | 
+                       NumberStyles.AllowDecimalPoint |
+                       NumberStyles.AllowLeadingSign;
+               
+               static readonly string [] datetimeFormats = {
+                 // dateTime
+                 "yyyy-MM-ddTHH:mm:ss",
+                 "yyyy-MM-ddTHH:mm:ss.f",
+                 "yyyy-MM-ddTHH:mm:ss.ff",
+                 "yyyy-MM-ddTHH:mm:ss.fff",
+                 "yyyy-MM-ddTHH:mm:ss.ffff",
+                 "yyyy-MM-ddTHH:mm:ss.fffff",
+                 "yyyy-MM-ddTHH:mm:ss.ffffff",
+                 "yyyy-MM-ddTHH:mm:ss.fffffff",
+                 "yyyy-MM-ddTHH:mm:sszzz",
+                 "yyyy-MM-ddTHH:mm:ss.fzzz",
+                 "yyyy-MM-ddTHH:mm:ss.ffzzz",
+                 "yyyy-MM-ddTHH:mm:ss.fffzzz",
+                 "yyyy-MM-ddTHH:mm:ss.ffffzzz",
+                 "yyyy-MM-ddTHH:mm:ss.fffffzzz",
+                 "yyyy-MM-ddTHH:mm:ss.ffffffzzz",
+                 "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
+                 "yyyy-MM-ddTHH:mm:ssZ",
+                 "yyyy-MM-ddTHH:mm:ss.fZ",
+                 "yyyy-MM-ddTHH:mm:ss.ffZ",
+                 "yyyy-MM-ddTHH:mm:ss.fffZ",
+                 "yyyy-MM-ddTHH:mm:ss.ffffZ",
+                 "yyyy-MM-ddTHH:mm:ss.fffffZ",
+                 "yyyy-MM-ddTHH:mm:ss.ffffffZ",
+                 "yyyy-MM-ddTHH:mm:ss.fffffffZ",
+                 // time
+                 "HH:mm:ss",
+                 "HH:mm:ss.f",
+                 "HH:mm:ss.ff",
+                 "HH:mm:ss.fff",
+                 "HH:mm:ss.ffff",
+                 "HH:mm:ss.fffff",
+                 "HH:mm:ss.ffffff",
+                 "HH:mm:ss.fffffff",
+                 "HH:mm:sszzz",
+                 "HH:mm:ss.fzzz",
+                 "HH:mm:ss.ffzzz",
+                 "HH:mm:ss.fffzzz",
+                 "HH:mm:ss.ffffzzz",
+                 "HH:mm:ss.fffffzzz",
+                 "HH:mm:ss.ffffffzzz",
+                 "HH:mm:ss.fffffffzzz",
+                 "HH:mm:ssZ",
+                 "HH:mm:ss.fZ",
+                 "HH:mm:ss.ffZ",
+                 "HH:mm:ss.fffZ",
+                 "HH:mm:ss.ffffZ",
+                 "HH:mm:ss.fffffZ",
+                 "HH:mm:ss.ffffffZ",
+                 "HH:mm:ss.fffffffZ",
+                 // date
+                 "yyyy-MM-dd",
+                 "yyyy-MM-ddzzz",
+                 "yyyy-MM-ddZ",
+                 // gYearMonth
+                 "yyyy-MM",
+                 "yyyy-MMzzz",
+                 "yyyy-MMZ",
+                 // gYear
+                 "yyyy",
+                 "yyyyzzz",
+                 "yyyyZ",
+                 // gMonthDay
+                 "--MM-dd",
+                 "--MM-ddzzz",
+                 "--MM-ddZ",
+                 // gDay
+                 "---dd",
+                 "---ddzzz",
+                 "---ddZ",
+               };
+               
                public XmlConvert()
                {}
 
@@ -108,7 +129,7 @@ namespace System.Xml {
 
                        char c = '\uFFFF';
                        try {
-                               c = (char) Int32.Parse (s.Substring (1, 4), NumberStyles.HexNumber);
+                               c = (char) Int32.Parse (s.Substring (1, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
                        } catch {
                                return s [0] + DecodeName (s.Substring (1));
                        }
@@ -127,7 +148,7 @@ namespace System.Xml {
                        if (pos == -1 || pos + 6 >= name.Length)
                                return name;
 
-                       if (Char.ToUpper (name [pos + 1]) != 'X' || name [pos + 6] != '_')
+                       if ((name [pos + 1] != 'X' && name [pos + 1] != 'x') || name [pos + 6] != '_')
                                return name [0] + DecodeName (name.Substring (1));
 
                        return name.Substring (0, pos) + TryDecoding (name.Substring (pos + 1));
@@ -135,6 +156,9 @@ namespace System.Xml {
 
                public static string EncodeLocalName (string name)
                {
+                       if (name == null)
+                               return name;
+
                        string encoded = EncodeName (name);
                        int pos = encoded.IndexOf (':');
                        if (pos == -1)
@@ -155,6 +179,9 @@ namespace System.Xml {
 
                private static string EncodeName (string name, bool nmtoken)
                {
+                       if (name == null || name.Length == 0)
+                               return name;
+
                        StringBuilder sb = new StringBuilder ();
                        int length = name.Length;
                        for (int i = 0; i < length; i++) {
@@ -174,8 +201,10 @@ namespace System.Xml {
                        return EncodeName (name, false);
                }
                
-               public static string EncodeNmToken(string name)
+               public static string EncodeNmToken (string name)
                {
+                       if (name == String.Empty)
+                               throw new XmlException ("Invalid NmToken: ''");
                        return EncodeName (name, true);
                }
 
@@ -198,6 +227,42 @@ namespace System.Xml {
                        }
                }
 
+               // LAMESPEC: It has been documented as public, but is marked as internal.
+               internal static string ToBinHexString (byte [] buffer)
+               {
+                       StringWriter w = new StringWriter ();
+                       WriteBinHex (buffer, 0, buffer.Length, w);
+                       return w.ToString ();
+               }
+
+               internal static void WriteBinHex (byte [] buffer, int index, int count, TextWriter w)
+               {
+                       if (buffer == null)
+                               throw new ArgumentNullException ("buffer");
+                       if (index < 0)
+                               throw new ArgumentOutOfRangeException ("index", index, "index must be non negative integer.");
+                       if (count < 0)
+                               throw new ArgumentOutOfRangeException ("count", count, "count must be non negative integer.");
+                       if (buffer.Length < index + count)
+                               throw new ArgumentOutOfRangeException ("index and count must be smaller than the length of the buffer.");
+
+                       // Copied from XmlTextWriter.WriteBinHex ()
+                       int end = index + count;
+                       for (int i = index; i < end; i++) {
+                               int val = buffer [i];
+                               int high = val >> 4;
+                               int low = val & 15;
+                               if (high > 9)
+                                       w.Write ((char) (high + 55));
+                               else
+                                       w.Write ((char) (high + 0x30));
+                               if (low > 9)
+                                       w.Write ((char) (low + 55));
+                               else
+                                       w.Write ((char) (low + 0x30));
+                       }
+               }
+
                public static byte ToByte(string s)
                {
                        return Byte.Parse(s, CultureInfo.InvariantCulture);
@@ -208,11 +273,30 @@ namespace System.Xml {
                        return Char.Parse(s);
                }
 
-               public static DateTime ToDateTime(string s)
+#if NET_2_0
+               [Obsolete]
+#endif
+               public static DateTime ToDateTime (string s)
                {
-                       return ToDateTime(s, datetimeFormats);
+                       return ToDateTime (s, datetimeFormats);
                }
                
+#if NET_2_0
+               public static DateTime ToDateTime (string value, XmlDateTimeSerializationMode mode)
+               {
+                       string modestr = null;
+                       switch (mode) {
+                       case XmlDateTimeSerializationMode.Local:
+                       case XmlDateTimeSerializationMode.RoundTripKind:
+                       default:
+                               return ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.fffffffzzz");
+                       case XmlDateTimeSerializationMode.Utc:
+                               return ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.fffffffZ").ToUniversalTime ();
+                       case XmlDateTimeSerializationMode.Unspecified:
+                               return ToDateTime (value, "yyyy-MM-ddTHH:mm:ss.fffffff");
+                       }
+               }
+#endif
                public static DateTime ToDateTime(string s, string format)
                {
                        DateTimeFormatInfo d = new DateTimeFormatInfo();
@@ -229,15 +313,20 @@ namespace System.Xml {
                
                public static Decimal ToDecimal(string s)
                {
-                       return Decimal.Parse(s, NumberFormatInfo.InvariantInfo);
+                       return Decimal.Parse(s, CultureInfo.InvariantCulture);
                }
-               
+
                public static double ToDouble(string s)
                {
-                       if (s == "INF") return System.Double.PositiveInfinity;
-                       if (s == "-INF") return System.Double.NegativeInfinity;
-                       if (s == "NaN") return System.Double.NaN;
-                       return Double.Parse(s, CultureInfo.InvariantCulture);
+                       if (s == null)
+                               throw new ArgumentNullException();
+                       if (s == "INF")
+                               return Double.PositiveInfinity;
+                       if (s == "-INF")
+                               return Double.NegativeInfinity;
+                       if (s == "NaN")
+                               return Double.NaN;
+                       return Double.Parse (s, floatStyle, CultureInfo.InvariantCulture);
                }
 
                public static Guid ToGuid(string s)
@@ -268,15 +357,20 @@ namespace System.Xml {
 
                public static float ToSingle(string s)
                {
-                       if (s == "INF") return System.Single.PositiveInfinity;
-                       if (s == "-INF") return System.Single.NegativeInfinity;
-                       if (s == "NaN") return System.Single.NaN;
-                       return Single.Parse(s, CultureInfo.InvariantCulture);
+                       if (s == null)
+                               throw new ArgumentNullException();
+                       if (s == "INF")
+                               return Single.PositiveInfinity;
+                       if (s == "-INF")
+                               return Single.NegativeInfinity;
+                       if (s == "NaN")
+                               return Single.NaN;
+                       return Single.Parse(s, floatStyle, CultureInfo.InvariantCulture);
                }
 
                public static string ToString(Guid value)
                {
-                       return value.ToString("D",CultureInfo.InvariantCulture);
+                       return value.ToString("D", CultureInfo.InvariantCulture);
                }
 
                public static string ToString(int value)
@@ -318,7 +412,7 @@ namespace System.Xml {
 
                public static string ToString(Decimal value)
                {
-                       return value.ToString(CultureInfo.InvariantCulture);
+                       return value.ToString (CultureInfo.InvariantCulture);
                }
 
                [CLSCompliant (false)]
@@ -327,26 +421,30 @@ namespace System.Xml {
                        return value.ToString(CultureInfo.InvariantCulture);
                }
 
-               public static string ToString(TimeSpan value)
+               public static string ToString (TimeSpan value)
                {
-                       StringBuilder builder = new StringBuilder();
+                       StringBuilder builder = new StringBuilder ();
                        if (value.Ticks < 0) {
-                               builder.Append('-');
-                               value = value.Negate();
+                               builder.Append ('-');
+                               value = value.Negate ();
                        }
-                       builder.Append('P');
-                       if (value.Days > 0) builder.Append(value.Days).Append('D');
-                       if (value.Days > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
+                       builder.Append ('P');
+                       if (value.Days > 0)
+                               builder.Append (value.Days).Append ('D');
+                       if (value.Days > 0 || value.Hours > 0 || value.Minutes > 0 || value.Seconds > 0 || value.Milliseconds > 0) {
                                builder.Append('T');
-                               if (value.Hours > 0) builder.Append(value.Hours).Append('D');
-                               if (value.Minutes > 0) builder.Append(value.Minutes).Append('M');
+                               if (value.Hours > 0)
+                                       builder.Append (value.Hours).Append ('H');
+                               if (value.Minutes > 0) 
+                                       builder.Append (value.Minutes).Append ('M');
                                if (value.Seconds > 0 || value.Milliseconds > 0) {
-                                       builder.Append(value.Seconds);
-                                       if (value.Milliseconds > 0) builder.Append('.').Append(String.Format("{0:000}", value.Milliseconds));
-                                       builder.Append('S');
+                                       builder.Append (value.Seconds);
+                                       if (value.Milliseconds > 0)
+                                               builder.Append ('.').AppendFormat ("{0:000}", value.Milliseconds);
+                                       builder.Append ('S');
                                }
                        }
-                       return builder.ToString();
+                       return builder.ToString ();
                }
 
                public static string ToString(double value)
@@ -354,7 +452,11 @@ namespace System.Xml {
                        if (Double.IsNegativeInfinity(value)) return "-INF";
                        if (Double.IsPositiveInfinity(value)) return "INF";
                        if (Double.IsNaN(value)) return "NaN";
+#if TARGET_JVM
+                       return value.ToString("R", NumberFormatInfo.InvariantInfo);
+#else
                        return value.ToString(CultureInfo.InvariantCulture);
+#endif
                }
 
                public static string ToString(float value)
@@ -362,7 +464,11 @@ namespace System.Xml {
                        if (Single.IsNegativeInfinity(value)) return "-INF";
                        if (Single.IsPositiveInfinity(value)) return "INF";
                        if (Single.IsNaN(value)) return "NaN";
+#if TARGET_JVM
+                       return value.ToString("R", NumberFormatInfo.InvariantInfo);
+#else
                        return value.ToString(CultureInfo.InvariantCulture);
+#endif
                }
 
                [CLSCompliant (false)]
@@ -377,10 +483,39 @@ namespace System.Xml {
                        return value.ToString(CultureInfo.InvariantCulture);
                }
 
-               public static string ToString(DateTime value)
-               {
-                       return value.ToString("yyyy-MM-ddTHH:mm:ss.fffffffzzz", CultureInfo.InvariantCulture);
+#if NET_2_0
+               [Obsolete]
+#endif
+               public static string ToString (DateTime value)
+               {
+                       return value.ToString ("yyyy-MM-ddTHH:mm:ss.fffffffzzz", CultureInfo.InvariantCulture);
+               }
+
+#if NET_2_0
+               public static string ToString (DateTime value, XmlDateTimeSerializationMode mode)
+               {
+                       string modestr = null;
+                       switch (mode) {
+                       case XmlDateTimeSerializationMode.Local:
+                       case XmlDateTimeSerializationMode.RoundTripKind:
+                       default:
+                               return value.ToString (
+                                       "yyyy-MM-ddTHH:mm:ss.fffffffzzz",
+                                       CultureInfo.InvariantCulture);
+                               break;
+                       case XmlDateTimeSerializationMode.Utc:
+                               return value.ToUniversalTime ().ToString (
+                                       "yyyy-MM-ddTHH:mm:ss.fffffffZ",
+                                       CultureInfo.InvariantCulture);
+                               break;
+                       case XmlDateTimeSerializationMode.Unspecified:
+                               return value.ToString (
+                                       "yyyy-MM-ddTHH:mm:ss.fffffff",
+                                       CultureInfo.InvariantCulture);
+                               break;
+                       }
                }
+#endif
 
                public static string ToString(DateTime value, string format)
                {
@@ -423,7 +558,7 @@ namespace System.Xml {
                                        if (!Char.IsDigit (s [i]))
                                                break;
                                }
-                               int value = int.Parse (s.Substring (start, i - start));
+                               int value = int.Parse (s.Substring (start, i - start), CultureInfo.InvariantCulture);
                                switch (s [i]) {
                                case 'Y':
                                        days += value * 365;
@@ -499,25 +634,40 @@ namespace System.Xml {
 
                public static string VerifyName (string name)
                {
-                       if(name == null)
+                       if (name == null)
                                throw new ArgumentNullException("name");
 
-                       if(!XmlChar.IsName (name))
+                       if (!XmlChar.IsName (name))
                                throw new XmlException("'" + name + "' is not a valid XML Name");
                        return name;
                        
                }
 
-               public static string VerifyNCName(string ncname)
+               public static string VerifyNCName (string ncname)
                {
-                       if(ncname == null)
+                       if (ncname == null)
                                throw new ArgumentNullException("ncname");
 
-                       if(!XmlChar.IsNCName (ncname))
+                       if (!XmlChar.IsNCName (ncname))
                                throw new XmlException ("'" + ncname + "' is not a valid XML NCName");
                        return ncname;
                }
 
+#if NET_2_0
+               public static string VerifyNMTOKEN (string name)
+#else
+               internal static string VerifyNMTOKEN (string name)
+#endif
+               {
+                       if (name == null)
+                               throw new ArgumentNullException("name");
+
+                       if (!XmlChar.IsNmToken (name))
+                               throw new XmlException("'" + name + "' is not a valid XML NMTOKEN");
+                       return name;
+                       
+               }
+
                // It is documented as public method, but in fact it is not.
                internal static byte [] FromBinHexString (string s)
                {