2 // System.Configuration.ConfigurationSettings.cs
5 // Christopher Podurgiel (cpodurgiel@msn.com)
6 // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 // Eric Lindvall (eric@5stops.com)
9 // (c) Christopher Podurgiel
10 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
11 // (c) 2003 Novell, Inc. (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 #if CONFIGURATION_DEP && !TARGET_JVM
36 extern alias PrebuiltSystem;
37 using NameValueCollection = PrebuiltSystem.System.Collections.Specialized.NameValueCollection;
41 using System.Collections;
42 using System.Collections.Specialized;
44 using System.Runtime.CompilerServices;
45 using System.Security.Permissions;
48 using System.Xml.XPath;
52 using vmw.@internal.io;
55 namespace System.Configuration
57 public sealed class ConfigurationSettings
60 static IConfigurationSystem config = DefaultConfig.GetInstance ();
62 static IConfigurationSystem config {
64 IConfigurationSystem conf = (IConfigurationSystem) AppDomain.CurrentDomain.GetData ("ConfigurationSettings.Config");
66 conf = DefaultConfig.GetInstance ();
67 AppDomain.CurrentDomain.SetData ("ConfigurationSettings.Config", conf);
72 AppDomain.CurrentDomain.SetData ("ConfigurationSettings.Config", value);
76 static object lockobj = new object ();
77 private ConfigurationSettings ()
81 [Obsolete ("This method is obsolete, it has been replaced by System.Configuration!System.Configuration.ConfigurationManager.GetSection")]
82 public static object GetConfig (string sectionName)
85 return ConfigurationManager.GetSection (sectionName);
87 return config.GetConfig (sectionName);
91 [Obsolete ("This property is obsolete. Please use System.Configuration.ConfigurationManager.AppSettings")]
92 public static NameValueCollection AppSettings
96 object appSettings = ConfigurationManager.GetSection ("appSettings");
98 object appSettings = GetConfig ("appSettings");
100 if (appSettings == null)
101 appSettings = new NameValueCollection ();
102 return (NameValueCollection) appSettings;
106 // Invoked from System.Web, disable warning
107 internal static IConfigurationSystem ChangeConfigurationSystem (IConfigurationSystem newSystem)
109 if (newSystem == null)
110 throw new ArgumentNullException ("newSystem");
113 IConfigurationSystem old = config;
121 // class DefaultConfig: read configuration from machine.config file and application
122 // config file if available.
124 class DefaultConfig : IConfigurationSystem
127 static readonly DefaultConfig instance = new DefaultConfig ();
129 static DefaultConfig instance {
131 DefaultConfig conf = (DefaultConfig) AppDomain.CurrentDomain.GetData ("DefaultConfig.instance");
133 conf = new DefaultConfig ();
134 AppDomain.CurrentDomain.SetData ("DefaultConfig.instance", conf);
139 AppDomain.CurrentDomain.SetData ("DefaultConfig.instance", value);
143 ConfigurationData config;
145 private DefaultConfig ()
149 public static DefaultConfig GetInstance ()
154 [Obsolete ("This method is obsolete. Please use System.Configuration.ConfigurationManager.GetConfig")]
155 public object GetConfig (string sectionName)
158 return config.GetConfig (sectionName);
167 ConfigurationData data = new ConfigurationData ();
168 if (data.LoadString (GetBundledMachineConfig ())) {
171 if (!data.Load (GetMachineConfigPath ()))
172 throw new ConfigurationException ("Cannot find " + GetMachineConfigPath ());
175 string appfile = GetAppConfigPath ();
176 if (appfile == null) {
181 ConfigurationData appData = new ConfigurationData (data);
182 if (appData.Load (appfile))
189 internal static string GetBundledMachineConfig ()
193 internal static string GetMachineConfigPath ()
195 return System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile;
198 [MethodImplAttribute(MethodImplOptions.InternalCall)]
199 extern private static string get_bundled_machine_config ();
200 internal static string GetBundledMachineConfig ()
202 return get_bundled_machine_config ();
204 [MethodImplAttribute(MethodImplOptions.InternalCall)]
205 extern private static string get_machine_config_path ();
206 internal static string GetMachineConfigPath ()
208 return get_machine_config_path ();
211 private static string GetAppConfigPath ()
213 AppDomainSetup currentInfo = AppDomain.CurrentDomain.SetupInformation;
215 string configFile = currentInfo.ConfigurationFile;
216 if (configFile == null || configFile.Length == 0)
233 public readonly string SectionName;
234 public readonly string TypeName;
235 public readonly bool AllowLocation;
236 public readonly AllowDefinition AllowDefinition;
238 public string FileName;
240 public readonly bool RequirePermission;
242 public SectionData (string sectionName, string typeName,
243 bool allowLocation, AllowDefinition allowDefinition, bool requirePermission)
245 SectionName = sectionName;
247 AllowLocation = allowLocation;
248 AllowDefinition = allowDefinition;
249 RequirePermission = requirePermission;
254 class ConfigurationData
256 ConfigurationData parent;
258 static object removedMark = new object ();
259 static object emptyMark = new object ();
263 static object groupMark = new object ();
267 Hashtable FileCache {
272 cache = new Hashtable ();
277 public ConfigurationData () : this (null)
281 public ConfigurationData (ConfigurationData parent)
283 this.parent = (parent == this) ? null : parent;
284 factories = new Hashtable ();
287 // SECURITY-FIXME: limit this with an imperative assert for reading the specific file
288 [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
289 public bool Load (string fileName)
292 this.fileName = fileName;
295 || !File.Exists (fileName)
300 XmlTextReader reader = null;
304 FileStream fs = new FileStream (fileName, FileMode.Open, FileAccess.Read);
306 Stream fs = (Stream) vmw.common.IOUtils.getStream (fileName);
308 //patch for machine.config
309 if (fs == null && fileName.EndsWith ("machine.config")) {
310 fs = (Stream) IOUtils.getStreamForGHConfigs (fileName);
317 reader = new XmlTextReader (fs);
318 if (InitRead (reader))
319 ReadConfigFile (reader);
320 } catch (ConfigurationException) {
322 } catch (Exception e) {
323 throw new ConfigurationException ("Error reading " + fileName, e);
332 public bool LoadString (string data)
337 XmlTextReader reader = null;
340 TextReader tr = new StringReader (data);
341 reader = new XmlTextReader (tr);
342 if (InitRead (reader))
343 ReadConfigFile (reader);
344 } catch (ConfigurationException) {
346 } catch (Exception e) {
347 throw new ConfigurationException ("Error reading " + fileName, e);
356 object GetHandler (string sectionName)
359 object o = factories [sectionName];
360 if (o == null || o == removedMark) {
362 return parent.GetHandler (sectionName);
367 if (o is IConfigurationSectionHandler)
368 return (IConfigurationSectionHandler) o;
370 o = CreateNewHandler (sectionName, (SectionData) o);
371 factories [sectionName] = o;
376 object CreateNewHandler (string sectionName, SectionData section)
378 Type t = Type.GetType (section.TypeName);
380 throw new ConfigurationException ("Cannot get Type for " + section.TypeName);
383 Type iconfig = typeof (IConfigurationSectionHandler);
384 if (!iconfig.IsAssignableFrom (t))
385 throw new ConfigurationException (sectionName + " does not implement " + iconfig);
388 object o = Activator.CreateInstance (t, true);
390 throw new ConfigurationException ("Cannot get instance for " + t);
395 XmlDocument GetInnerDoc (XmlDocument doc, int i, string [] sectionPath)
397 if (++i >= sectionPath.Length)
400 if (doc.DocumentElement == null)
403 XmlNode node = doc.DocumentElement.FirstChild;
404 while (node != null) {
405 if (node.Name == sectionPath [i]) {
406 ConfigXmlDocument result = new ConfigXmlDocument ();
407 result.Load (new StringReader (node.OuterXml));
408 return GetInnerDoc (result, i, sectionPath);
410 node = node.NextSibling;
416 XmlDocument GetDocumentForSection (string sectionName)
418 ConfigXmlDocument doc = new ConfigXmlDocument ();
422 string [] sectionPath = sectionName.Split ('/');
423 string outerxml = pending [sectionPath [0]] as string;
424 if (outerxml == null)
427 StringReader reader = new StringReader (outerxml);
428 XmlTextReader rd = new XmlTextReader (reader);
430 doc.LoadSingleElement (fileName, rd);
432 return GetInnerDoc (doc, 0, sectionPath);
435 object GetConfigInternal (string sectionName)
437 object handler = GetHandler (sectionName);
438 IConfigurationSectionHandler iconf = handler as IConfigurationSectionHandler;
442 object parentConfig = null;
444 parentConfig = parent.GetConfig (sectionName);
446 XmlDocument doc = GetDocumentForSection (sectionName);
447 if (doc == null || doc.DocumentElement == null)
450 return iconf.Create (parentConfig, fileName, doc.DocumentElement);
453 object GetConfigInternal (string sectionName)
458 public object GetConfig (string sectionName)
462 config = this.FileCache [sectionName];
465 if (config == emptyMark)
472 config = GetConfigInternal (sectionName);
473 this.FileCache [sectionName] = (config == null) ? emptyMark : config;
479 private object LookForFactory (string key)
481 object o = factories [key];
486 return parent.LookForFactory (key);
491 private bool InitRead (XmlTextReader reader)
493 reader.MoveToContent ();
494 if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration")
495 ThrowException ("Configuration file does not have a valid root element", reader);
497 if (reader.HasAttributes)
498 ThrowException ("Unrecognized attribute in root element", reader);
499 if (reader.IsEmptyElement) {
504 reader.MoveToContent ();
505 return reader.NodeType != XmlNodeType.EndElement;
508 // FIXME: this approach is not always safe and likely to cause bugs.
509 private void MoveToNextElement (XmlTextReader reader)
511 while (reader.Read ()) {
512 XmlNodeType ntype = reader.NodeType;
513 if (ntype == XmlNodeType.Element)
516 if (ntype != XmlNodeType.Whitespace &&
517 ntype != XmlNodeType.Comment &&
518 ntype != XmlNodeType.SignificantWhitespace &&
519 ntype != XmlNodeType.EndElement)
520 ThrowException ("Unrecognized element", reader);
524 private void ReadSection (XmlTextReader reader, string sectionName)
527 string nameValue = null;
528 string typeValue = null;
529 string allowLoc = null, allowDef = null;
530 bool requirePermission = false;
531 string requirePer = null;
532 bool allowLocation = true;
533 AllowDefinition allowDefinition = AllowDefinition.Everywhere;
535 while (reader.MoveToNextAttribute ()) {
536 attName = reader.Name;
540 if (attName == "allowLocation") {
541 if (allowLoc != null)
542 ThrowException ("Duplicated allowLocation attribute.", reader);
544 allowLoc = reader.Value;
545 allowLocation = (allowLoc == "true");
546 if (!allowLocation && allowLoc != "false")
547 ThrowException ("Invalid attribute value", reader);
552 if (attName == "requirePermission") {
553 if (requirePer != null)
554 ThrowException ("Duplicated requirePermission attribute.", reader);
555 requirePer = reader.Value;
556 requirePermission = (requirePer == "true");
557 if (!requirePermission && requirePer != "false")
558 ThrowException ("Invalid attribute value", reader);
562 if (attName == "allowDefinition") {
563 if (allowDef != null)
564 ThrowException ("Duplicated allowDefinition attribute.", reader);
566 allowDef = reader.Value;
568 allowDefinition = (AllowDefinition) Enum.Parse (
569 typeof (AllowDefinition), allowDef);
571 ThrowException ("Invalid attribute value", reader);
577 if (attName == "type") {
578 if (typeValue != null)
579 ThrowException ("Duplicated type attribute.", reader);
580 typeValue = reader.Value;
584 if (attName == "name") {
585 if (nameValue != null)
586 ThrowException ("Duplicated name attribute.", reader);
587 nameValue = reader.Value;
588 if (nameValue == "location")
589 ThrowException ("location is a reserved section name", reader);
593 ThrowException ("Unrecognized attribute.", reader);
596 if (nameValue == null || typeValue == null)
597 ThrowException ("Required attribute missing", reader);
599 if (sectionName != null)
600 nameValue = sectionName + '/' + nameValue;
602 reader.MoveToElement();
603 object o = LookForFactory (nameValue);
604 if (o != null && o != removedMark)
605 ThrowException ("Already have a factory for " + nameValue, reader);
606 SectionData section = new SectionData (nameValue, typeValue, allowLocation,
607 allowDefinition, requirePermission);
608 section.FileName = fileName;
609 factories [nameValue] = section;
611 if (reader.IsEmptyElement)
615 reader.MoveToContent ();
616 if (reader.NodeType != XmlNodeType.EndElement)
617 // sub-section inside a section
618 ReadSections (reader, nameValue);
619 reader.ReadEndElement ();
621 reader.MoveToContent ();
624 private void ReadRemoveSection (XmlTextReader reader, string sectionName)
626 if (!reader.MoveToNextAttribute () || reader.Name != "name")
627 ThrowException ("Unrecognized attribute.", reader);
629 string removeValue = reader.Value;
630 if (removeValue == null || removeValue.Length == 0)
631 ThrowException ("Empty name to remove", reader);
633 reader.MoveToElement ();
635 if (sectionName != null)
636 removeValue = sectionName + '/' + removeValue;
638 object o = LookForFactory (removeValue);
639 if (o != null && o == removedMark)
640 ThrowException ("No factory for " + removeValue, reader);
642 factories [removeValue] = removedMark;
643 MoveToNextElement (reader);
646 private void ReadSectionGroup (XmlTextReader reader, string configSection)
648 if (!reader.MoveToNextAttribute ())
649 ThrowException ("sectionGroup must have a 'name' attribute.", reader);
653 if (reader.Name == "name") {
655 ThrowException ("Duplicate 'name' attribute.", reader);
656 value = reader.Value;
659 if (reader.Name != "type")
660 ThrowException ("Unrecognized attribute.", reader);
661 } while (reader.MoveToNextAttribute ());
664 ThrowException ("No 'name' attribute.", reader);
666 if (value == "location")
667 ThrowException ("location is a reserved section name", reader);
669 if (configSection != null)
670 value = configSection + '/' + value;
672 object o = LookForFactory (value);
673 if (o != null && o != removedMark && o != groupMark)
674 ThrowException ("Already have a factory for " + value, reader);
676 factories [value] = groupMark;
678 if (reader.IsEmptyElement) {
680 reader.MoveToContent ();
683 reader.MoveToContent ();
684 if (reader.NodeType != XmlNodeType.EndElement)
685 ReadSections (reader, value);
686 reader.ReadEndElement ();
687 reader.MoveToContent ();
691 // It stops XmlReader consumption at where it found
692 // surrounding EndElement i.e. EndElement is not consumed here
693 private void ReadSections (XmlTextReader reader, string configSection)
695 int depth = reader.Depth;
696 for (reader.MoveToContent ();
697 reader.Depth == depth;
698 reader.MoveToContent ()) {
699 string name = reader.Name;
700 if (name == "section") {
701 ReadSection (reader, configSection);
705 if (name == "remove") {
706 ReadRemoveSection (reader, configSection);
710 if (name == "clear") {
711 if (reader.HasAttributes)
712 ThrowException ("Unrecognized attribute.", reader);
715 MoveToNextElement (reader);
719 if (name == "sectionGroup") {
720 ReadSectionGroup (reader, configSection);
725 ThrowException ("Unrecognized element: " + reader.Name, reader);
729 void StorePending (string name, XmlTextReader reader)
732 pending = new Hashtable ();
734 pending [name] = reader.ReadOuterXml ();
737 private void ReadConfigFile (XmlTextReader reader)
739 //int depth = reader.Depth;
740 for (reader.MoveToContent ();
741 !reader.EOF && reader.NodeType != XmlNodeType.EndElement;
742 reader.MoveToContent ()) {
743 string name = reader.Name;
744 if (name == "configSections") {
745 if (reader.HasAttributes)
746 ThrowException ("Unrecognized attribute in <configSections>.", reader);
747 if (reader.IsEmptyElement)
751 reader.MoveToContent ();
752 if (reader.NodeType != XmlNodeType.EndElement)
753 ReadSections (reader, null);
754 reader.ReadEndElement ();
756 } else if (name != null && name != "") {
757 StorePending (name, reader);
758 MoveToNextElement (reader);
760 MoveToNextElement (reader);
765 private void ThrowException (string text, XmlTextReader reader)
767 throw new ConfigurationException (text, fileName, reader.LineNumber);