[Xml] Fix GetAttribute to handle null namespaces properly, add unit test.
[mono.git] / mcs / class / System.XML / System.Xml / XmlDeclaration.cs
index 54fa83e960aa0ccbcfd997afae919d46e2483cb5..821d82e2eb6cdf1585a782478d3115f7928c0e4b 100644 (file)
-//\r
-// System.Xml.XmlDeclaration\r
-//\r
-// Author:\r
-//     Duncan Mak  (duncan@ximian.com)\r
-//\r
-// (C) Ximian, Inc.\r
-\r
-using System;\r
-using System.Xml;\r
-\r
-namespace System.Xml\r
-{\r
-       public class XmlDeclaration : XmlLinkedNode\r
-       {\r
-               string encoding = "UTF-8"; // defaults to UTF-8\r
-               string standAlone;\r
-               string version;\r
-\r
-               protected internal XmlDeclaration (string version, string encoding,\r
-                                                  string standAlone, XmlDocument doc)\r
-                       : base (doc)\r
-               {\r
-                       this.version = version;\r
-                       this.encoding = encoding;\r
-                       this.standAlone = standAlone;\r
-               }\r
-\r
-               public string Encoding  {\r
-                       get {\r
-                               if (encoding == null)\r
-                                       return String.Empty;\r
-                               else\r
-                                       return encoding;\r
-                       } \r
-\r
-                       set { encoding = value ; } // Note: MS' doesn't check this string, should we?\r
-               }\r
-\r
-               public override string InnerText {\r
-                       get { return Value; }\r
-                       set { ParseInput (value); }\r
-               }\r
-               \r
-               public override string LocalName {\r
-                       get { return "xml"; }\r
-               }\r
-\r
-               public override string Name {\r
-                       get { return "xml"; }\r
-               }\r
-\r
-               public override XmlNodeType NodeType {\r
-                       get { return XmlNodeType.XmlDeclaration; }\r
-               }\r
-\r
-               public string Standalone {\r
-                       get {\r
-                               if (standAlone == null)\r
-                                       return String.Empty;\r
-                               else\r
-                                       return standAlone;\r
-                       }\r
-\r
-                       set {\r
-                               if (value.ToUpper() == "YES")\r
-                                       standAlone = "yes";\r
-                               if (value.ToUpper() == "NO")\r
-                                       standAlone = "no";\r
-                       }\r
-               }\r
-\r
-               public override string Value {\r
-                       get { return String.Format ("version=\"{0}\" encoding=\"{1}\" standalone=\"{2}\"",\r
-                                                   Version, Encoding, Standalone); }\r
-                       set { ParseInput (value); }\r
-               }\r
-\r
-               public string Version {\r
-                       get { return version; }\r
-               }\r
-\r
-               public override XmlNode CloneNode (bool deep)\r
-               {\r
-                       return new XmlDeclaration (Encoding, standAlone, OwnerDocument);\r
-               }\r
-\r
-               public override void WriteContentTo (XmlWriter w)\r
-               {\r
-                       // Nothing to do - no children.\r
-               }\r
-\r
-               [MonoTODO]\r
-               public override void WriteTo (XmlWriter w)\r
-               {\r
-                       if ((Standalone == String.Empty) || (Encoding == String.Empty))\r
-                               return;\r
-               }\r
-\r
-               void ParseInput (string input)\r
-               {                       \r
-                       Encoding = input.Split (new char [] { ' ' }) [1].Split (new char [] { '=' }) [1];\r
-                       Standalone = input.Split (new char [] { ' ' }) [2].Split (new char [] { '=' }) [1];\r
-               }\r
-       }\r
-}\r
+//
+// System.Xml.XmlDeclaration
+//
+// Author:
+//     Duncan Mak  (duncan@ximian.com)
+//     Atsushi Enomotot  (atsushi@ximian.com)
+//
+// (C) Ximian, Inc.
+
+//
+// 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.Globalization;
+using System.Text;
+using System.Xml;
+
+namespace System.Xml
+{
+       public class XmlDeclaration : XmlLinkedNode
+       {
+               string encoding = "UTF-8"; // defaults to UTF-8
+               string standalone;
+               string version;
+
+               protected internal XmlDeclaration (string version, string encoding,
+                                                  string standalone, XmlDocument doc)
+                       : base (doc)
+               {
+                       if (encoding == null)
+                               encoding = "";
+
+                       if (standalone == null)
+                               standalone = "";
+
+                       this.version = version;
+                       this.encoding = encoding;
+                       this.standalone = standalone;
+               }
+
+               public string Encoding  {
+                       get { return encoding; } 
+                       set { encoding = (value == null) ? String.Empty : value; }
+               }
+
+               public override string InnerText {
+                       get { return Value; }
+                       set { ParseInput (value); }
+               }
+               
+               public override string LocalName {
+                       get { return "xml"; }
+               }
+
+               public override string Name {
+                       get { return "xml"; }
+               }
+
+               public override XmlNodeType NodeType {
+                       get { return XmlNodeType.XmlDeclaration; }
+               }
+
+               public string Standalone {
+                       get { return standalone; }
+                       set {
+                               if(value != null)
+                               {
+                                       if (String.Compare (value, "YES", true, CultureInfo.InvariantCulture) == 0)
+                                               standalone = "yes";
+                                       if (String.Compare (value, "NO", true, CultureInfo.InvariantCulture) == 0)
+                                               standalone = "no";
+                               }
+                               else
+                                       standalone = String.Empty;
+                       }
+               }
+
+               public override string Value {
+                       get {
+                               string formatEncoding = "";
+                               string formatStandalone = "";
+
+                               if (encoding != String.Empty)
+                                       formatEncoding = String.Format (" encoding=\"{0}\"", encoding);
+
+                               if (standalone != String.Empty)
+                                       formatStandalone = String.Format (" standalone=\"{0}\"", standalone);
+
+                               return String.Format ("version=\"{0}\"{1}{2}", Version, formatEncoding, formatStandalone);
+                       }
+                       set { ParseInput (value); }
+               }
+
+               public string Version {
+                       get { return version; }
+               }
+
+               public override XmlNode CloneNode (bool deep)
+               {
+                       return new XmlDeclaration (Version, Encoding, standalone, OwnerDocument);
+               }
+
+               public override void WriteContentTo (XmlWriter w) {}
+
+               public override void WriteTo (XmlWriter w)
+               {
+                       // This doesn't seem to match up very well with w.WriteStartDocument()
+                       // so writing out custom here.
+                       w.WriteRaw (String.Format ("<?xml {0}?>", Value));
+               }
+
+               private int SkipWhitespace (string input, int index)
+               {
+                       while (index < input.Length) {
+                               if (XmlChar.IsWhitespace (input [index]))
+                                       index++;
+                               else
+                                       break;
+                       }
+                       return index;
+               }
+
+               void ParseInput (string input)
+               {
+                       int index = SkipWhitespace (input, 0);
+                       if (index + 7 > input.Length || input.IndexOf ("version", index, 7) != index)
+                               throw new XmlException ("Missing 'version' specification.");
+                       index = SkipWhitespace (input, index + 7);
+
+                       char c = input [index];
+                       if (c != '=')
+                               throw new XmlException ("Invalid 'version' specification.");
+                       index++;
+                       index = SkipWhitespace (input, index);
+                       c = input [index];
+                       if (c != '"' && c != '\'')
+                               throw new XmlException ("Invalid 'version' specification.");
+                       index++;
+                       int end = input.IndexOf (c, index);
+                       if (end < 0 || input.IndexOf ("1.0", index, 3) != index)
+                               throw new XmlException ("Invalid 'version' specification.");
+                       index += 4;
+                       if (index == input.Length)
+                               return;
+                       if (!XmlChar.IsWhitespace (input [index]))
+                               throw new XmlException ("Invalid XML declaration.");
+                       index = SkipWhitespace (input, index + 1);
+                       if (index == input.Length)
+                               return;
+
+                       if (input.Length > index + 8 && input.IndexOf ("encoding", index, 8) > 0) {
+                               index = SkipWhitespace (input, index + 8);
+                               c = input [index];
+                               if (c != '=')
+                                       throw new XmlException ("Invalid 'version' specification.");
+                               index++;
+                               index = SkipWhitespace (input, index);
+                               c = input [index];
+                               if (c != '"' && c != '\'')
+                                       throw new XmlException ("Invalid 'encoding' specification.");
+                               end = input.IndexOf (c, index + 1);
+                               if (end < 0)
+                                       throw new XmlException ("Invalid 'encoding' specification.");
+                               Encoding = input.Substring (index + 1, end - index - 1);
+                               index = end + 1;
+                               if (index == input.Length)
+                                       return;
+                               if (!XmlChar.IsWhitespace (input [index]))
+                                       throw new XmlException ("Invalid XML declaration.");
+                               index = SkipWhitespace (input, index + 1);
+                       }
+
+                       if (input.Length > index + 10 && input.IndexOf ("standalone", index, 10) > 0) {
+                               index = SkipWhitespace (input, index + 10);
+                               c = input [index];
+                               if (c != '=')
+                                       throw new XmlException ("Invalid 'version' specification.");
+                               index++;
+                               index = SkipWhitespace (input, index);
+                               c = input [index];
+                               if (c != '"' && c != '\'')
+                                       throw new XmlException ("Invalid 'standalone' specification.");
+                               end = input.IndexOf (c, index + 1);
+                               if (end < 0)
+                                       throw new XmlException ("Invalid 'standalone' specification.");
+                               string tmp = input.Substring (index + 1, end - index - 1);
+                               switch (tmp) {
+                               case "yes":
+                               case "no":
+                                       break;
+                               default:
+                                       throw new XmlException ("Invalid standalone specification.");
+                               }
+                               Standalone = tmp;
+                               index = end + 1;
+                               index = SkipWhitespace (input, index);
+                       }
+                       if (index != input.Length)
+                               throw new XmlException ("Invalid XML declaration.");
+               }
+       }
+}