Merge pull request #644 from knocte/connstrings
[mono.git] / mcs / class / System.Configuration / System.Configuration / ConfigurationSection.cs
index 4e9c46f5c3d49088b9deb06df8ea2a6f42819986..8a76dd6fff5a0ff29f7e323a158db89ce1b61e52 100644 (file)
@@ -3,7 +3,8 @@
 //
 // Authors:
 //     Duncan Mak (duncan@ximian.com)
-//  Lluis Sanchez Gual (lluis@novell.com)
+//     Lluis Sanchez Gual (lluis@novell.com)
+//     Martin Baulig <martin.baulig@xamarin.com>
 //
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (c) 2012 Xamarin Inc. (http://www.xamarin.com)
 //
 
-#if NET_2_0
 using System.Collections;
 using System.Xml;
 using System.IO;
 #if !TARGET_JVM
 using System.Security.Cryptography.Xml;
 #endif
+using System.Configuration.Internal;
 
 namespace System.Configuration
 {
@@ -41,11 +43,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 +66,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 +135,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 +177,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());
@@ -142,13 +234,53 @@ namespace System.Configuration
                        else
                                elem = this;
 
-                       StringWriter sw = new StringWriter ();
-                       XmlTextWriter tw = new XmlTextWriter (sw);
-                       tw.Formatting = Formatting.Indented;
-                       elem.SerializeToXmlElement (tw, name);
-                       tw.Close ();
-                       return sw.ToString ();
+                       /*
+                        * FIXME: LAMESPEC
+                        * 
+                        * Cache the current values of 'parentElement' and 'saveMode' for later use in
+                        * ConfigurationElement.SerializeToXmlElement().
+                        * 
+                        */
+                       elem.PrepareSave (parentElement, saveMode);
+                       bool hasValues = elem.HasValues (parentElement, saveMode);
+
+                       string ret;                     
+                       using (StringWriter sw = new StringWriter ()) {
+                               using (XmlTextWriter tw = new XmlTextWriter (sw)) {
+                                       tw.Formatting = Formatting.Indented;
+                                       if (hasValues)
+                                               elem.SerializeToXmlElement (tw, name);
+                                       else if ((saveMode == ConfigurationSaveMode.Modified) && elem.IsModified ()) {
+                                               // MS emits an empty section element.
+                                               tw.WriteStartElement (name);
+                                               tw.WriteEndElement ();
+                                       }
+                                       tw.Close ();
+                               }
+                               
+                               ret = sw.ToString ();
+                       }
+                       
+                       string config_source = SectionInformation.ConfigSource;
+                       
+                       if (String.IsNullOrEmpty (config_source))
+                               return ret;
+
+                       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 ();
+                       }
                }
        }
 }
-#endif
+