BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / System / System.Configuration / ConfigurationSettings.cs
1 //
2 // System.Configuration.ConfigurationSettings.cs
3 //
4 // Author:
5 //   Christopher Podurgiel (cpodurgiel@msn.com)
6 //   Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 //   Eric Lindvall (eric@5stops.com)
8 //
9 // (c) Christopher Podurgiel
10 // (c) 2002 Ximian, Inc. (http://www.ximian.com)
11 // (c) 2003 Novell, Inc. (http://www.novell.com)
12 //
13
14 //
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:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
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.
33 //
34
35 #if CONFIGURATION_DEP && !TARGET_JVM
36 extern alias PrebuiltSystem;
37 using NameValueCollection = PrebuiltSystem.System.Collections.Specialized.NameValueCollection;
38 #endif
39
40 using System;
41 using System.Collections;
42 using System.Collections.Specialized;
43 using System.IO;
44 using System.Runtime.CompilerServices;
45 using System.Security.Permissions;
46 #if (XML_DEP)
47 using System.Xml;
48 using System.Xml.XPath;
49 #endif
50 #if TARGET_JVM
51 using vmw.common;
52 using vmw.@internal.io;
53 #endif
54
55 namespace System.Configuration
56 {
57         public sealed class ConfigurationSettings
58         {
59 #if !TARGET_JVM
60                 static IConfigurationSystem config = DefaultConfig.GetInstance ();
61 #else
62                 static IConfigurationSystem config {
63                         get {
64                                 IConfigurationSystem conf = (IConfigurationSystem) AppDomain.CurrentDomain.GetData ("ConfigurationSettings.Config");
65                                 if (conf == null) {
66                                         conf = DefaultConfig.GetInstance ();
67                                         AppDomain.CurrentDomain.SetData ("ConfigurationSettings.Config", conf);
68                                 }
69                                 return conf;
70                         }
71                         set {
72                                 AppDomain.CurrentDomain.SetData ("ConfigurationSettings.Config", value);
73                         }
74                 }
75 #endif
76                 static object lockobj = new object ();
77                 private ConfigurationSettings ()
78                 {
79                 }
80
81 #if NET_2_0
82                 [Obsolete ("This method is obsolete, it has been replaced by System.Configuration!System.Configuration.ConfigurationManager.GetSection")]
83 #endif
84                 public static object GetConfig (string sectionName)
85                 {
86 #if NET_2_0 && CONFIGURATION_DEP
87                         return ConfigurationManager.GetSection (sectionName);
88 #else
89                         return config.GetConfig (sectionName);
90 #endif
91                 }
92
93 #if NET_2_0
94                 [Obsolete ("This property is obsolete.  Please use System.Configuration.ConfigurationManager.AppSettings")]
95 #endif
96                 public static NameValueCollection AppSettings
97                 {
98                         get {
99 #if NET_2_0 && CONFIGURATION_DEP
100                                 object appSettings = ConfigurationManager.GetSection ("appSettings");
101 #else
102                                 object appSettings = GetConfig ("appSettings");
103 #endif
104                                 if (appSettings == null)
105                                         appSettings = new NameValueCollection ();
106                                 return (NameValueCollection) appSettings;
107                         }
108                 }
109
110                 // Invoked from System.Web, disable warning
111                 internal static IConfigurationSystem ChangeConfigurationSystem (IConfigurationSystem newSystem)
112                 {
113                         if (newSystem == null)
114                                 throw new ArgumentNullException ("newSystem");
115
116                         lock (lockobj) {
117                                 IConfigurationSystem old = config;
118                                 config = newSystem;
119                                 return old;
120                         }
121                 }
122         }
123
124         //
125         // class DefaultConfig: read configuration from machine.config file and application
126         // config file if available.
127         //
128         class DefaultConfig : IConfigurationSystem
129         {
130 #if !TARGET_JVM
131                 static readonly DefaultConfig instance = new DefaultConfig ();        
132 #else
133                 static DefaultConfig instance {
134                         get {
135                                 DefaultConfig conf = (DefaultConfig) AppDomain.CurrentDomain.GetData ("DefaultConfig.instance");
136                                 if (conf == null) {
137                                         conf = new DefaultConfig ();
138                                         AppDomain.CurrentDomain.SetData ("DefaultConfig.instance", conf);
139                                 }
140                                 return conf;
141                         }
142                         set {
143                                 AppDomain.CurrentDomain.SetData ("DefaultConfig.instance", value);
144                         }
145                 }
146 #endif
147                 ConfigurationData config;
148                 
149                 private DefaultConfig ()
150                 {
151                 }
152
153                 public static DefaultConfig GetInstance ()
154                 {
155                         return instance;
156                 }
157
158 #if NET_2_0
159                 [Obsolete ("This method is obsolete.  Please use System.Configuration.ConfigurationManager.GetConfig")]
160 #endif
161                 public object GetConfig (string sectionName)
162                 {
163                         Init ();
164                         return config.GetConfig (sectionName);
165                 }
166
167                 public void Init ()
168                 {
169                         lock (this) {
170                                 if (config != null)
171                                         return;
172
173                                 ConfigurationData data = new ConfigurationData ();
174                                 if (data.LoadString (GetBundledMachineConfig ())) {
175                                         // do nothing
176                                 } else {
177                                         if (!data.Load (GetMachineConfigPath ()))
178                                                 throw new ConfigurationException ("Cannot find " + GetMachineConfigPath ());
179
180                                 }
181                                 string appfile = GetAppConfigPath ();
182                                 if (appfile == null) {
183                                         config = data;
184                                         return;
185                                 }
186
187                                 ConfigurationData appData = new ConfigurationData (data);
188                                 if (appData.Load (appfile))
189                                         config = appData;
190                                 else
191                                         config = data;
192                         }
193                 }
194 #if TARGET_JVM
195                 internal static string GetBundledMachineConfig ()
196                 {
197                         return null;
198                 }
199                 internal static string GetMachineConfigPath ()
200                 {
201                         return System.Runtime.InteropServices.RuntimeEnvironment.SystemConfigurationFile;
202                 }
203 #else
204                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
205                 extern private static string get_bundled_machine_config ();
206                 internal static string GetBundledMachineConfig ()
207                 {
208                         return get_bundled_machine_config ();
209                 }
210                 [MethodImplAttribute(MethodImplOptions.InternalCall)]
211                 extern private static string get_machine_config_path ();
212                 internal static string GetMachineConfigPath ()
213                 {
214                         return get_machine_config_path ();
215                 }
216 #endif
217                 private static string GetAppConfigPath ()
218                 {
219                         AppDomainSetup currentInfo = AppDomain.CurrentDomain.SetupInformation;
220
221                         string configFile = currentInfo.ConfigurationFile;
222                         if (configFile == null || configFile.Length == 0)
223                                 return null;
224
225                         return configFile;
226
227                 }
228         }
229
230         enum AllowDefinition
231         {
232                 Everywhere,
233                 MachineOnly,
234                 MachineToApplication
235         }
236
237         class SectionData
238         {
239                 public readonly string SectionName;
240                 public readonly string TypeName;
241                 public readonly bool AllowLocation;
242                 public readonly AllowDefinition AllowDefinition;
243 #if XML_DEP
244                 public string FileName;
245 #endif
246                 public readonly bool RequirePermission;
247
248                 public SectionData (string sectionName, string typeName,
249                             bool allowLocation, AllowDefinition allowDefinition, bool requirePermission)
250                 {
251                         SectionName = sectionName;
252                         TypeName = typeName;
253                         AllowLocation = allowLocation;
254                         AllowDefinition = allowDefinition;
255                         RequirePermission = requirePermission;
256                 }
257         }
258
259
260         class ConfigurationData
261         {
262                 ConfigurationData parent;
263                 Hashtable factories;
264                 static object removedMark = new object ();
265                 static object emptyMark = new object ();
266 #if (XML_DEP)
267                 Hashtable pending;
268                 string fileName;
269                 static object groupMark = new object ();
270 #endif
271                 Hashtable cache;
272
273                 Hashtable FileCache {
274                         get {
275                                 if (cache != null)
276                                         return cache;
277
278                                 cache = new Hashtable ();
279                                 return cache;
280                         }
281                 }
282
283                 public ConfigurationData () : this (null)
284                 {
285                 }
286
287                 public ConfigurationData (ConfigurationData parent)
288                 {
289                         this.parent = (parent == this) ? null : parent;
290                         factories = new Hashtable ();
291                 }
292
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)
296                 {
297 #if (XML_DEP)
298                         this.fileName = fileName;
299                         if (fileName == null
300 #if !TARGET_JVM
301                                 || !File.Exists (fileName)
302 #endif
303 )
304                                 return false;
305                         
306                         XmlTextReader reader = null;
307
308                         try {
309 #if !TARGET_JVM
310                                 FileStream fs = new FileStream (fileName, FileMode.Open, FileAccess.Read);
311 #else
312                                 Stream fs = (Stream) vmw.common.IOUtils.getStream (fileName);
313
314                                 //patch for machine.config
315                                 if (fs == null && fileName.EndsWith ("machine.config")) {
316                                         fs = (Stream) IOUtils.getStreamForGHConfigs (fileName);
317                                 }
318
319                                 if (fs == null) {
320                                         return false;
321                                 }
322 #endif
323                                 reader = new XmlTextReader (fs);
324                                 if (InitRead (reader))
325                                         ReadConfigFile (reader);
326                         } catch (ConfigurationException) {
327                                 throw;
328                         } catch (Exception e) {
329                                 throw new ConfigurationException ("Error reading " + fileName, e);
330                         } finally {
331                                 if (reader != null)
332                                         reader.Close();
333                         }
334 #endif
335                         return true;
336                 }
337                 
338                 public bool LoadString (string data)
339                 {
340                         if (data == null)
341                                 return false;
342 #if (XML_DEP)
343                         XmlTextReader reader = null;
344
345                         try {
346                                 TextReader tr = new StringReader (data);
347                                 reader = new XmlTextReader (tr);
348                                 if (InitRead (reader))
349                                         ReadConfigFile (reader);
350                         } catch (ConfigurationException) {
351                                 throw;
352                         } catch (Exception e) {
353                                 throw new ConfigurationException ("Error reading " + fileName, e);
354                         } finally {
355                                 if (reader != null)
356                                         reader.Close();
357                         }
358 #endif
359                         return true;
360                 }
361                 
362                 object GetHandler (string sectionName)
363                 {
364                         lock (factories) {
365                                 object o = factories [sectionName];
366                                 if (o == null || o == removedMark) {
367                                         if (parent != null)
368                                                 return parent.GetHandler (sectionName);
369
370                                         return null;
371                                 }
372
373                                 if (o is IConfigurationSectionHandler)
374                                         return (IConfigurationSectionHandler) o;
375
376                                 o = CreateNewHandler (sectionName, (SectionData) o);
377                                 factories [sectionName] = o;
378                                 return o;
379                         }
380                 }
381
382                 object CreateNewHandler (string sectionName, SectionData section)
383                 {
384                         Type t = Type.GetType (section.TypeName);
385                         if (t == null)
386                                 throw new ConfigurationException ("Cannot get Type for " + section.TypeName);
387
388 #if false
389                         Type iconfig = typeof (IConfigurationSectionHandler);
390                         if (!iconfig.IsAssignableFrom (t))
391                                 throw new ConfigurationException (sectionName + " does not implement " + iconfig);
392 #endif
393                         
394                         object o = Activator.CreateInstance (t, true);
395                         if (o == null)
396                                 throw new ConfigurationException ("Cannot get instance for " + t);
397
398                         return o;
399                 }
400 #if (XML_DEP)
401                 XmlDocument GetInnerDoc (XmlDocument doc, int i, string [] sectionPath)
402                 {
403                         if (++i >= sectionPath.Length)
404                                 return doc;
405
406                         if (doc.DocumentElement == null)
407                                 return null;
408
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);
415                                 }
416                                 node = node.NextSibling;
417                         }
418
419                         return null;
420                 }
421
422                 XmlDocument GetDocumentForSection (string sectionName)
423                 {
424                         ConfigXmlDocument doc = new ConfigXmlDocument ();
425                         if (pending == null)
426                                 return doc;
427
428                         string [] sectionPath = sectionName.Split ('/');
429                         string outerxml = pending [sectionPath [0]] as string;
430                         if (outerxml == null)
431                                 return doc;
432
433                         StringReader reader = new StringReader (outerxml);
434                         XmlTextReader rd = new XmlTextReader (reader);
435                         rd.MoveToContent ();
436                         doc.LoadSingleElement (fileName, rd);
437
438                         return GetInnerDoc (doc, 0, sectionPath);
439                 }
440                 
441                 object GetConfigInternal (string sectionName)
442                 {
443                         object handler = GetHandler (sectionName);
444                         IConfigurationSectionHandler iconf = handler as IConfigurationSectionHandler;
445                         if (iconf == null)
446                                 return handler;
447
448                         object parentConfig = null;
449                         if (parent != null)
450                                 parentConfig = parent.GetConfig (sectionName);
451
452                         XmlDocument doc = GetDocumentForSection (sectionName);
453                         if (doc == null || doc.DocumentElement == null)
454                                 return parentConfig;
455                         
456                         return iconf.Create (parentConfig, fileName, doc.DocumentElement);
457                 }
458 #else
459                 object GetConfigInternal (string sectionName)
460                 {
461                     return null;
462                 }
463 #endif
464                 public object GetConfig (string sectionName)
465                 {
466                         object config;
467                         lock (this) {
468                                 config = this.FileCache [sectionName];
469                         }
470
471                         if (config == emptyMark)
472                                 return null;
473
474                         if (config != null)
475                                 return config;
476
477                         lock (this) {
478                                 config = GetConfigInternal (sectionName);
479                                 this.FileCache [sectionName] = (config == null) ? emptyMark : config;
480                         }
481
482                         return config;
483                 }
484
485                 private object LookForFactory (string key)
486                 {
487                         object o = factories [key];
488                         if (o != null)
489                                 return o;
490
491                         if (parent != null)
492                                 return parent.LookForFactory (key);
493
494                         return null;
495                 }
496 #if (XML_DEP)
497                 private bool InitRead (XmlTextReader reader)
498                 {
499                         reader.MoveToContent ();
500                         if (reader.NodeType != XmlNodeType.Element || reader.Name != "configuration")
501                                 ThrowException ("Configuration file does not have a valid root element", reader);
502
503                         if (reader.HasAttributes)
504                                 ThrowException ("Unrecognized attribute in root element", reader);
505                         if (reader.IsEmptyElement) {
506                                 reader.Skip ();
507                                 return false;
508                         }
509                         reader.Read ();
510                         reader.MoveToContent ();
511                         return reader.NodeType != XmlNodeType.EndElement;
512                 }
513
514                 // FIXME: this approach is not always safe and likely to cause bugs.
515                 private void MoveToNextElement (XmlTextReader reader)
516                 {
517                         while (reader.Read ()) {
518                                 XmlNodeType ntype = reader.NodeType;
519                                 if (ntype == XmlNodeType.Element)
520                                         return;
521
522                                 if (ntype != XmlNodeType.Whitespace &&
523                                     ntype != XmlNodeType.Comment &&
524                                     ntype != XmlNodeType.SignificantWhitespace &&
525                                     ntype != XmlNodeType.EndElement)
526                                         ThrowException ("Unrecognized element", reader);
527                         }
528                 }
529
530                 private void ReadSection (XmlTextReader reader, string sectionName)
531                 {
532                         string attName;
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;
540
541                         while (reader.MoveToNextAttribute ()) {
542                                 attName = reader.Name;
543                                 if (attName == null)
544                                         continue;
545
546                                 if (attName == "allowLocation") {
547                                         if (allowLoc != null)
548                                                 ThrowException ("Duplicated allowLocation attribute.", reader);
549
550                                         allowLoc = reader.Value;
551                                         allowLocation = (allowLoc == "true");
552                                         if (!allowLocation && allowLoc != "false")
553                                                 ThrowException ("Invalid attribute value", reader);
554
555                                         continue;
556                                 }
557
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);
565                                         continue;
566                                 }
567
568                                 if (attName == "allowDefinition") {
569                                         if (allowDef != null)
570                                                 ThrowException ("Duplicated allowDefinition attribute.", reader);
571
572                                         allowDef = reader.Value;
573                                         try {
574                                                 allowDefinition = (AllowDefinition) Enum.Parse (
575                                                                    typeof (AllowDefinition), allowDef);
576                                         } catch {
577                                                 ThrowException ("Invalid attribute value", reader);
578                                         }
579
580                                         continue;
581                                 }
582
583                                 if (attName == "type")  {
584                                         if (typeValue != null)
585                                                 ThrowException ("Duplicated type attribute.", reader);
586                                         typeValue = reader.Value;
587                                         continue;
588                                 }
589                                 
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);
596                                         continue;
597                                 }
598
599                                 ThrowException ("Unrecognized attribute.", reader);
600                         }
601
602                         if (nameValue == null || typeValue == null)
603                                 ThrowException ("Required attribute missing", reader);
604
605                         if (sectionName != null)
606                                 nameValue = sectionName + '/' + nameValue;
607
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;
616
617                         if (reader.IsEmptyElement)
618                                 reader.Skip ();
619                         else {
620                                 reader.Read ();
621                                 reader.MoveToContent ();
622                                 if (reader.NodeType != XmlNodeType.EndElement)
623                                         // sub-section inside a section
624                                         ReadSections (reader, nameValue);
625                                 reader.ReadEndElement ();
626                         }
627                         reader.MoveToContent ();
628                 }
629
630                 private void ReadRemoveSection (XmlTextReader reader, string sectionName)
631                 {
632                         if (!reader.MoveToNextAttribute () || reader.Name != "name")
633                                 ThrowException ("Unrecognized attribute.", reader);
634
635                         string removeValue = reader.Value;
636                         if (removeValue == null || removeValue.Length == 0)
637                                 ThrowException ("Empty name to remove", reader);
638
639                         reader.MoveToElement ();
640
641                         if (sectionName != null)
642                                 removeValue = sectionName + '/' + removeValue;
643
644                         object o = LookForFactory (removeValue);
645                         if (o != null && o == removedMark)
646                                 ThrowException ("No factory for " + removeValue, reader);
647
648                         factories [removeValue] = removedMark;
649                         MoveToNextElement (reader);
650                 }
651
652                 private void ReadSectionGroup (XmlTextReader reader, string configSection)
653                 {
654                         if (!reader.MoveToNextAttribute ())
655                                 ThrowException ("sectionGroup must have a 'name' attribute.", reader);
656
657                         string value = null;
658                         do {
659                                 if (reader.Name == "name") {
660                                         if (value != null)
661                                                 ThrowException ("Duplicate 'name' attribute.", reader);
662                                         value = reader.Value;
663                                 }
664                                 else
665 #if NET_2_0
666                                 if (reader.Name != "type")
667 #endif
668                                         ThrowException ("Unrecognized attribute.", reader);
669                         } while (reader.MoveToNextAttribute ());
670
671                         if (value == null)
672                                 ThrowException ("No 'name' attribute.", reader);
673                         
674                         if (value == "location")
675                                 ThrowException ("location is a reserved section name", reader);
676
677                         if (configSection != null)
678                                 value = configSection + '/' + value;
679
680                         object o = LookForFactory (value);
681                         if (o != null && o != removedMark && o != groupMark)
682                                 ThrowException ("Already have a factory for " + value, reader);
683
684                         factories [value] = groupMark;
685
686                         if (reader.IsEmptyElement) {
687                                 reader.Skip ();
688                                 reader.MoveToContent ();
689                         } else {
690                                 reader.Read ();
691                                 reader.MoveToContent ();
692                                 if (reader.NodeType != XmlNodeType.EndElement)
693                                         ReadSections (reader, value);
694                                 reader.ReadEndElement ();
695                                 reader.MoveToContent ();
696                         }
697                 }
698
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)
702                 {
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);
710                                         continue;
711                                 } 
712                                 
713                                 if (name == "remove") {
714                                         ReadRemoveSection (reader, configSection);
715                                         continue;
716                                 }
717
718                                 if (name == "clear") {
719                                         if (reader.HasAttributes)
720                                                 ThrowException ("Unrecognized attribute.", reader);
721
722                                         factories.Clear ();
723                                         MoveToNextElement (reader);
724                                         continue;
725                                 }
726
727                                 if (name == "sectionGroup") {
728                                         ReadSectionGroup (reader, configSection);
729                                         continue;
730                                 }
731                                 
732
733                                 ThrowException ("Unrecognized element: " + reader.Name, reader);
734                         }
735                 }
736
737                 void StorePending (string name, XmlTextReader reader)
738                 {
739                         if (pending == null)
740                                 pending = new Hashtable ();
741
742                         pending [name] = reader.ReadOuterXml ();
743                 }
744
745                 private void ReadConfigFile (XmlTextReader reader)
746                 {
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)
756                                                 reader.Skip ();
757                                         else {
758                                                 reader.Read ();
759                                                 reader.MoveToContent ();
760                                                 if (reader.NodeType != XmlNodeType.EndElement)
761                                                         ReadSections (reader, null);
762                                                 reader.ReadEndElement ();
763                                         }
764                                 } else if (name != null && name != "") {
765                                         StorePending (name, reader);
766                                         MoveToNextElement (reader);
767                                 } else {
768                                         MoveToNextElement (reader);
769                                 }
770                         }
771                 }
772                 
773                 private void ThrowException (string text, XmlTextReader reader)
774                 {
775                         throw new ConfigurationException (text, fileName, reader.LineNumber);
776                 }
777 #endif
778         }
779 }
780
781