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 ()
82 [Obsolete ("This method is obsolete, it has been replaced by System.Configuration!System.Configuration.ConfigurationManager.GetSection")]
84 public static object GetConfig (string sectionName)
86 #if NET_2_0 && CONFIGURATION_DEP
87 return ConfigurationManager.GetSection (sectionName);
89 return config.GetConfig (sectionName);
94 [Obsolete ("This property is obsolete. Please use System.Configuration.ConfigurationManager.AppSettings")]
96 public static NameValueCollection AppSettings
99 #if NET_2_0 && CONFIGURATION_DEP
100 object appSettings = ConfigurationManager.GetSection ("appSettings");
102 object appSettings = GetConfig ("appSettings");
104 if (appSettings == null)
105 appSettings = new NameValueCollection ();
106 return (NameValueCollection) appSettings;
110 // Invoked from System.Web, disable warning
111 internal static IConfigurationSystem ChangeConfigurationSystem (IConfigurationSystem newSystem)
113 if (newSystem == null)
114 throw new ArgumentNullException ("newSystem");
117 IConfigurationSystem old = config;
125 // class DefaultConfig: read configuration from machine.config file and application
126 // config file if available.
128 class DefaultConfig : IConfigurationSystem
131 static readonly DefaultConfig instance = new DefaultConfig ();
133 static DefaultConfig instance {
135 DefaultConfig conf = (DefaultConfig) AppDomain.CurrentDomain.GetData ("DefaultConfig.instance");
137 conf = new DefaultConfig ();
138 AppDomain.CurrentDomain.SetData ("DefaultConfig.instance", conf);
143 AppDomain.CurrentDomain.SetData ("DefaultConfig.instance", value);
147 ConfigurationData config;
149 private DefaultConfig ()
153 public static DefaultConfig GetInstance ()
159 [Obsolete ("This method is obsolete. Please use System.Configuration.ConfigurationManager.GetConfig")]
161 public object GetConfig (string sectionName)
164 return config.GetConfig (sectionName);
173 ConfigurationData data = new ConfigurationData ();
174 if (data.LoadString (GetBundledMachineConfig ())) {
177 if (!data.Load (GetMachineConfigPath ()))
178 throw new ConfigurationException ("Cannot find " + GetMachineConfigPath ());
181 string appfile = GetAppConfigPath ();
182 if (appfile == null) {
187 ConfigurationData appData = new ConfigurationData (data);
188 if (appData.Load (appfile))
195 internal static string GetBundledMachineConfig ()
199 internal static string GetMachineConfigPath ()
201 return System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile;
204 [MethodImplAttribute(MethodImplOptions.InternalCall)]
205 extern private static string get_bundled_machine_config ();
206 internal static string GetBundledMachineConfig ()
208 return get_bundled_machine_config ();
210 [MethodImplAttribute(MethodImplOptions.InternalCall)]
211 extern private static string get_machine_config_path ();
212 internal static string GetMachineConfigPath ()
214 return get_machine_config_path ();
217 private static string GetAppConfigPath ()
219 AppDomainSetup currentInfo = AppDomain.CurrentDomain.SetupInformation;
221 string configFile = currentInfo.ConfigurationFile;
222 if (configFile == null || configFile.Length == 0)
239 public readonly string SectionName;
240 public readonly string TypeName;
241 public readonly bool AllowLocation;
242 public readonly AllowDefinition AllowDefinition;
244 public string FileName;
246 public readonly bool RequirePermission;
248 public SectionData (string sectionName, string typeName,
249 bool allowLocation, AllowDefinition allowDefinition, bool requirePermission)
251 SectionName = sectionName;
253 AllowLocation = allowLocation;
254 AllowDefinition = allowDefinition;
255 RequirePermission = requirePermission;
260 class ConfigurationData
262 ConfigurationData parent;
264 static object removedMark = new object ();
265 static object emptyMark = new object ();
269 static object groupMark = new object ();
273 Hashtable FileCache {
278 cache = new Hashtable ();
283 public ConfigurationData () : this (null)
287 public ConfigurationData (ConfigurationData parent)
289 this.parent = (parent == this) ? null : parent;
290 factories = new Hashtable ();
293 // SECURITY-FIXME: limit this with an imperative assert for reading the specific file
294 [FileIOPermission (SecurityAction.Assert, Unrestricted = true)]
295 public bool Load (string fileName)
298 this.fileName = fileName;
301 || !File.Exists (fileName)
306 XmlTextReader reader = null;
310 FileStream fs = new FileStream (fileName, FileMode.Open, FileAccess.Read);
312 Stream fs = (Stream) vmw.common.IOUtils.getStream (fileName);
314 //patch for machine.config
315 if (fs == null && fileName.EndsWith ("machine.config")) {
316 fs = (Stream) IOUtils.getStreamForGHConfigs (fileName);
323 reader = new XmlTextReader (fs);
324 if (InitRead (reader))
325 ReadConfigFile (reader);
326 } catch (ConfigurationException) {
328 } catch (Exception e) {
329 throw new ConfigurationException ("Error reading " + fileName, e);
338 public bool LoadString (string data)
343 XmlTextReader reader = null;
346 TextReader tr = new StringReader (data);
347 reader = new XmlTextReader (tr);
348 if (InitRead (reader))
349 ReadConfigFile (reader);
350 } catch (ConfigurationException) {
352 } catch (Exception e) {
353 throw new ConfigurationException ("Error reading " + fileName, e);
362 object GetHandler (string sectionName)
365 object o = factories [sectionName];
366 if (o == null || o == removedMark) {
368 return parent.GetHandler (sectionName);
373 if (o is IConfigurationSectionHandler)
374 return (IConfigurationSectionHandler) o;
376 o = CreateNewHandler (sectionName, (SectionData) o);
377 factories [sectionName] = o;
382 object CreateNewHandler (string sectionName, SectionData section)
384 Type t = Type.GetType (section.TypeName);
386 throw new ConfigurationException ("Cannot get Type for " + section.TypeName);
389 Type iconfig = typeof (IConfigurationSectionHandler);
390 if (!iconfig.IsAssignableFrom (t))
391 throw new ConfigurationException (sectionName + " does not implement " + iconfig);
394 object o = Activator.CreateInstance (t, true);
396 throw new ConfigurationException ("Cannot get instance for " + t);
401 XmlDocument GetInnerDoc (XmlDocument doc, int i, string [] sectionPath)
403 if (++i >= sectionPath.Length)
406 if (doc.DocumentElement == null)
409 XmlNode node = doc.DocumentElement.FirstChild;
410 while (node != null) {
411 if (node.Name == sectionPath [i]) {
412 ConfigXmlDocument result = new ConfigXmlDocument ();
413 result.Load (new StringReader (node.OuterXml));
414 return GetInnerDoc (result, i, sectionPath);
416 node = node.NextSibling;
422 XmlDocument GetDocumentForSection (string sectionName)
424 ConfigXmlDocument doc = new ConfigXmlDocument ();
428 string [] sectionPath = sectionName.Split ('/');
429 string outerxml = pending [sectionPath [0]] as string;
430 if (outerxml == null)
433 StringReader reader = new StringReader (outerxml);
434 XmlTextReader rd = new XmlTextReader (reader);
436 doc.LoadSingleElement (fileName, rd);
438 return GetInnerDoc (doc, 0, sectionPath);
441 object GetConfigInternal (string sectionName)
443 object handler = GetHandler (sectionName);
444 IConfigurationSectionHandler iconf = handler as IConfigurationSectionHandler;
448 object parentConfig = null;
450 parentConfig = parent.GetConfig (sectionName);
452 XmlDocument doc = GetDocumentForSection (sectionName);
453 if (doc == null || doc.DocumentElement == null)
456 return iconf.Create (parentConfig, fileName, doc.DocumentElement);
459 object GetConfigInternal (string sectionName)
464 public object GetConfig (string sectionName)
468 config = this.FileCache [sectionName];
471 if (config == emptyMark)
478 config = GetConfigInternal (sectionName);
479 this.FileCache [sectionName] = (config == null) ? emptyMark : config;
485 private object LookForFactory (string key)
487 object o = factories [key];
492 return parent.LookForFactory (key);
497 private bool InitRead (XmlTextReader reader)
499 reader.MoveToContent ();
500 if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration")
501 ThrowException ("Configuration file does not have a valid root element", reader);
503 if (reader.HasAttributes)
504 ThrowException ("Unrecognized attribute in root element", reader);
505 if (reader.IsEmptyElement) {
510 reader.MoveToContent ();
511 return reader.NodeType != XmlNodeType.EndElement;
514 // FIXME: this approach is not always safe and likely to cause bugs.
515 private void MoveToNextElement (XmlTextReader reader)
517 while (reader.Read ()) {
518 XmlNodeType ntype = reader.NodeType;
519 if (ntype == XmlNodeType.Element)
522 if (ntype != XmlNodeType.Whitespace &&
523 ntype != XmlNodeType.Comment &&
524 ntype != XmlNodeType.SignificantWhitespace &&
525 ntype != XmlNodeType.EndElement)
526 ThrowException ("Unrecognized element", reader);
530 private void ReadSection (XmlTextReader reader, string sectionName)
533 string nameValue = null;
534 string typeValue = null;
535 string allowLoc = null, allowDef = null;
536 bool requirePermission = false;
537 string requirePer = null;
538 bool allowLocation = true;
539 AllowDefinition allowDefinition = AllowDefinition.Everywhere;
541 while (reader.MoveToNextAttribute ()) {
542 attName = reader.Name;
546 if (attName == "allowLocation") {
547 if (allowLoc != null)
548 ThrowException ("Duplicated allowLocation attribute.", reader);
550 allowLoc = reader.Value;
551 allowLocation = (allowLoc == "true");
552 if (!allowLocation && allowLoc != "false")
553 ThrowException ("Invalid attribute value", reader);
558 if (attName == "requirePermission") {
559 if (requirePer != null)
560 ThrowException ("Duplicated requirePermission attribute.", reader);
561 requirePer = reader.Value;
562 requirePermission = (requirePer == "true");
563 if (!requirePermission && requirePer != "false")
564 ThrowException ("Invalid attribute value", reader);
568 if (attName == "allowDefinition") {
569 if (allowDef != null)
570 ThrowException ("Duplicated allowDefinition attribute.", reader);
572 allowDef = reader.Value;
574 allowDefinition = (AllowDefinition) Enum.Parse (
575 typeof (AllowDefinition), allowDef);
577 ThrowException ("Invalid attribute value", reader);
583 if (attName == "type") {
584 if (typeValue != null)
585 ThrowException ("Duplicated type attribute.", reader);
586 typeValue = reader.Value;
590 if (attName == "name") {
591 if (nameValue != null)
592 ThrowException ("Duplicated name attribute.", reader);
593 nameValue = reader.Value;
594 if (nameValue == "location")
595 ThrowException ("location is a reserved section name", reader);
599 ThrowException ("Unrecognized attribute.", reader);
602 if (nameValue == null || typeValue == null)
603 ThrowException ("Required attribute missing", reader);
605 if (sectionName != null)
606 nameValue = sectionName + '/' + nameValue;
608 reader.MoveToElement();
609 object o = LookForFactory (nameValue);
610 if (o != null && o != removedMark)
611 ThrowException ("Already have a factory for " + nameValue, reader);
612 SectionData section = new SectionData (nameValue, typeValue, allowLocation,
613 allowDefinition, requirePermission);
614 section.FileName = fileName;
615 factories [nameValue] = section;
617 if (reader.IsEmptyElement)
621 reader.MoveToContent ();
622 if (reader.NodeType != XmlNodeType.EndElement)
623 // sub-section inside a section
624 ReadSections (reader, nameValue);
625 reader.ReadEndElement ();
627 reader.MoveToContent ();
630 private void ReadRemoveSection (XmlTextReader reader, string sectionName)
632 if (!reader.MoveToNextAttribute () || reader.Name != "name")
633 ThrowException ("Unrecognized attribute.", reader);
635 string removeValue = reader.Value;
636 if (removeValue == null || removeValue.Length == 0)
637 ThrowException ("Empty name to remove", reader);
639 reader.MoveToElement ();
641 if (sectionName != null)
642 removeValue = sectionName + '/' + removeValue;
644 object o = LookForFactory (removeValue);
645 if (o != null && o == removedMark)
646 ThrowException ("No factory for " + removeValue, reader);
648 factories [removeValue] = removedMark;
649 MoveToNextElement (reader);
652 private void ReadSectionGroup (XmlTextReader reader, string configSection)
654 if (!reader.MoveToNextAttribute ())
655 ThrowException ("sectionGroup must have a 'name' attribute.", reader);
659 if (reader.Name == "name") {
661 ThrowException ("Duplicate 'name' attribute.", reader);
662 value = reader.Value;
666 if (reader.Name != "type")
668 ThrowException ("Unrecognized attribute.", reader);
669 } while (reader.MoveToNextAttribute ());
672 ThrowException ("No 'name' attribute.", reader);
674 if (value == "location")
675 ThrowException ("location is a reserved section name", reader);
677 if (configSection != null)
678 value = configSection + '/' + value;
680 object o = LookForFactory (value);
681 if (o != null && o != removedMark && o != groupMark)
682 ThrowException ("Already have a factory for " + value, reader);
684 factories [value] = groupMark;
686 if (reader.IsEmptyElement) {
688 reader.MoveToContent ();
691 reader.MoveToContent ();
692 if (reader.NodeType != XmlNodeType.EndElement)
693 ReadSections (reader, value);
694 reader.ReadEndElement ();
695 reader.MoveToContent ();
699 // It stops XmlReader consumption at where it found
700 // surrounding EndElement i.e. EndElement is not consumed here
701 private void ReadSections (XmlTextReader reader, string configSection)
703 int depth = reader.Depth;
704 for (reader.MoveToContent ();
705 reader.Depth == depth;
706 reader.MoveToContent ()) {
707 string name = reader.Name;
708 if (name == "section") {
709 ReadSection (reader, configSection);
713 if (name == "remove") {
714 ReadRemoveSection (reader, configSection);
718 if (name == "clear") {
719 if (reader.HasAttributes)
720 ThrowException ("Unrecognized attribute.", reader);
723 MoveToNextElement (reader);
727 if (name == "sectionGroup") {
728 ReadSectionGroup (reader, configSection);
733 ThrowException ("Unrecognized element: " + reader.Name, reader);
737 void StorePending (string name, XmlTextReader reader)
740 pending = new Hashtable ();
742 pending [name] = reader.ReadOuterXml ();
745 private void ReadConfigFile (XmlTextReader reader)
747 //int depth = reader.Depth;
748 for (reader.MoveToContent ();
749 !reader.EOF && reader.NodeType != XmlNodeType.EndElement;
750 reader.MoveToContent ()) {
751 string name = reader.Name;
752 if (name == "configSections") {
753 if (reader.HasAttributes)
754 ThrowException ("Unrecognized attribute in <configSections>.", reader);
755 if (reader.IsEmptyElement)
759 reader.MoveToContent ();
760 if (reader.NodeType != XmlNodeType.EndElement)
761 ReadSections (reader, null);
762 reader.ReadEndElement ();
764 } else if (name != null && name != "") {
765 StorePending (name, reader);
766 MoveToNextElement (reader);
768 MoveToNextElement (reader);
773 private void ThrowException (string text, XmlTextReader reader)
775 throw new ConfigurationException (text, fileName, reader.LineNumber);