Merge pull request #498 from Unroll-Me/master
[mono.git] / mcs / class / System.Configuration / System.Configuration / ConfigurationSection.cs
index 4e9c46f5c3d49088b9deb06df8ea2a6f42819986..84723f85aa5e8ae7698f977578ee6ca21c7e28cd 100644 (file)
@@ -34,6 +34,7 @@ using System.IO;
 #if !TARGET_JVM
 using System.Security.Cryptography.Xml;
 #endif
+using System.Configuration.Internal;
 
 namespace System.Configuration
 {
@@ -41,11 +42,16 @@ namespace System.Configuration
        {
                SectionInformation sectionInformation;
                IConfigurationSectionHandler section_handler;
-
+               string externalDataXml;
+               
                protected ConfigurationSection ()
                {
                }
 
+               internal string ExternalDataXml {
+                       get { return externalDataXml; }
+               }
+               
                internal IConfigurationSectionHandler SectionHandler {
                        get { return section_handler; }
                        set { section_handler = value; }
@@ -59,18 +65,55 @@ namespace System.Configuration
                                return sectionInformation;
                        }
                }
+               
+               private object _configContext;
+               
+               internal object ConfigContext {
+                       get {
+                               return _configContext;
+                       }
+                       set {
+                               _configContext = value;
+                       }
+               }
 
-               [MonoTODO]
+               [MonoTODO ("Provide ConfigContext. Likely the culprit of bug #322493")]
                protected internal virtual object GetRuntimeObject ()
                {
-                       // FIXME: this hack is nasty. We should make some
-                       // refactory on the entire assembly.
                        if (SectionHandler != null) {
+                               ConfigurationSection parentSection = sectionInformation != null ? sectionInformation.GetParentSection () : null;
+                               object parent = parentSection != null ? parentSection.GetRuntimeObject () : null;
                                if (RawXml == null)
-                                       return null;
-                               XmlDocument doc = new XmlDocument ();
+                                       return parent;
+                               
+                               try {
+                                       // This code requires some re-thinking...
+                                       XmlReader reader = new ConfigXmlTextReader (
+                                               new StringReader (RawXml),
+                                               Configuration.FilePath);
+
+                                       DoDeserializeSection (reader);
+                                       
+                                       if (!String.IsNullOrEmpty (SectionInformation.ConfigSource)) {
+                                               string fileDir = SectionInformation.ConfigFilePath;
+                                               if (!String.IsNullOrEmpty (fileDir))
+                                                       fileDir = Path.GetDirectoryName (fileDir);
+                                               else
+                                                       fileDir = String.Empty;
+                                       
+                                               string path = Path.Combine (fileDir, SectionInformation.ConfigSource);
+                                               if (File.Exists (path)) {
+                                                       RawXml = File.ReadAllText (path);
+                                                       SectionInformation.SetRawXml (RawXml);
+                                               }
+                                       }
+                               } catch {
+                                       // ignore, it can fail - we deserialize only in order to get
+                                       // the configSource attribute
+                               }
+                               XmlDocument doc = new ConfigurationXmlDocument ();
                                doc.LoadXml (RawXml);
-                               return SectionHandler.Create (null, null, doc.DocumentElement);
+                               return SectionHandler.Create (parent, ConfigContext, doc.DocumentElement);
                        }
                        return this;
                }
@@ -91,28 +134,33 @@ namespace System.Configuration
                {
                        ConfigurationElement elem = (ConfigurationElement) Activator.CreateInstance (t);
                        elem.Init ();
+                       elem.Configuration = Configuration;
                        if (IsReadOnly ())
                                elem.SetReadOnly ();
                        return elem;
                }
 
-               [MonoTODO ("find the proper location for the decryption stuff")]
-               protected internal virtual void DeserializeSection (XmlReader reader)
+               void DoDeserializeSection (XmlReader reader)
                {
                        reader.MoveToContent ();
 
+                       string protection_provider = null;
+                       string config_source = null;
+                       string localName;
+                       
+                       while (reader.MoveToNextAttribute ()) {
+                               localName = reader.LocalName;
+                               if (localName == "configProtectionProvider")
+                                       protection_provider = reader.Value;
+                               else if (localName == "configSource")
+                                       config_source = reader.Value;
+                       }
+
                        /* XXX this stuff shouldn't be here */
                        {
-                               string protection_provider = null;
-
-                               while (reader.MoveToNextAttribute ()) {
-                                       if (reader.LocalName == "configProtectionProvider")
-                                               protection_provider = reader.Value;
-                               }
-
                                if (protection_provider != null) {
                                        ProtectedConfigurationProvider prov = ProtectedConfiguration.GetProvider (protection_provider, true);
-                                       XmlDocument doc = new XmlDocument ();
+                                       XmlDocument doc = new ConfigurationXmlDocument ();
 
                                        reader.MoveToElement ();
 
@@ -128,12 +176,55 @@ namespace System.Configuration
                                }
                        }
 
+                       if (config_source != null)
+                               SectionInformation.ConfigSource = config_source;
+                       
                        SectionInformation.SetRawXml (RawXml);
-                       DeserializeElement (reader, false);
+                       if (SectionHandler == null)
+                               DeserializeElement (reader, false);
+               }
+               
+               [MonoInternalNote ("find the proper location for the decryption stuff")]
+               protected internal virtual void DeserializeSection (XmlReader reader)
+               {
+                       try
+                       {
+                               DoDeserializeSection (reader);
+                       }
+                       catch (ConfigurationErrorsException ex)
+                       {
+                               throw new ConfigurationErrorsException(String.Format("Error deserializing configuration section {0}: {1}", this.SectionInformation.Name, ex.Message));
+                       }
                }
 
+               internal void DeserializeConfigSource (string basePath)
+               {
+                       string config_source = SectionInformation.ConfigSource;
+
+                       if (String.IsNullOrEmpty (config_source))
+                               return;
+
+                       if (Path.IsPathRooted (config_source))
+                               throw new ConfigurationErrorsException ("The configSource attribute must be a relative physical path.");
+                       
+                       if (HasLocalModifications ())
+                               throw new ConfigurationErrorsException ("A section using 'configSource' may contain no other attributes or elements.");
+                       
+                       string path = Path.Combine (basePath, config_source);
+                       if (!File.Exists (path)) {
+                               RawXml = null;
+                               SectionInformation.SetRawXml (null);
+                               throw new ConfigurationErrorsException (string.Format ("Unable to open configSource file '{0}'.", path));
+                       }
+                       
+                       RawXml = File.ReadAllText (path);
+                       SectionInformation.SetRawXml (RawXml);
+                       DeserializeElement (new ConfigXmlTextReader (new StringReader (RawXml), path), false);
+               }
+               
                protected internal virtual string SerializeSection (ConfigurationElement parentElement, string name, ConfigurationSaveMode saveMode)
                {
+                       externalDataXml = null;
                        ConfigurationElement elem;
                        if (parentElement != null) {
                                elem = (ConfigurationElement) CreateElement (GetType());
@@ -141,13 +232,37 @@ namespace System.Configuration
                        }
                        else
                                elem = this;
+                       
+                       string ret;                     
+                       using (StringWriter sw = new StringWriter ()) {
+                               using (XmlTextWriter tw = new XmlTextWriter (sw)) {
+                                       tw.Formatting = Formatting.Indented;
+                                       elem.SerializeToXmlElement (tw, name);
+                                       tw.Close ();
+                               }
+                               
+                               ret = sw.ToString ();
+                       }
+                       
+                       string config_source = SectionInformation.ConfigSource;
+                       
+                       if (String.IsNullOrEmpty (config_source))
+                               return ret;
 
-                       StringWriter sw = new StringWriter ();
-                       XmlTextWriter tw = new XmlTextWriter (sw);
-                       tw.Formatting = Formatting.Indented;
-                       elem.SerializeToXmlElement (tw, name);
-                       tw.Close ();
-                       return sw.ToString ();
+                       externalDataXml = ret;
+                       using (StringWriter sw = new StringWriter ()) {
+                               bool haveName = !String.IsNullOrEmpty (name);
+
+                               using (XmlTextWriter tw = new XmlTextWriter (sw)) {
+                                       if (haveName)
+                                               tw.WriteStartElement (name);
+                                       tw.WriteAttributeString ("configSource", config_source);
+                                       if (haveName)
+                                               tw.WriteEndElement ();
+                               }
+
+                               return sw.ToString ();
+                       }
                }
        }
 }