merge -r 58784:58785
[mono.git] / mcs / class / System.Configuration / System.Configuration / SectionGroupInfo.cs
1 //
2 // System.Configuration.SectionGroupInfo.cs
3 //
4 // Authors:
5 //      Lluis Sanchez (lluis@novell.com)
6 //
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
14 // 
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
17 // 
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 //
26 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
27 //
28 #if NET_2_0
29 using System;
30 using System.Collections;
31 using System.Collections.Specialized;
32 using System.Xml;
33 using System.IO;
34 using System.Text;
35
36 namespace System.Configuration
37 {
38         internal class SectionGroupInfo: ConfigInfo
39         {
40                 ConfigInfoCollection sections;
41                 ConfigInfoCollection groups;
42                 static ConfigInfoCollection emptyList = new ConfigInfoCollection ();
43
44                 public SectionGroupInfo ()
45                 {
46                         Type = typeof (ConfigurationSectionGroup);
47                 }
48                 
49                 public SectionGroupInfo (string groupName, string typeName)
50                 {
51                         Name = groupName;
52                         TypeName = typeName;
53                 }
54                 
55                 public void AddChild (ConfigInfo data)
56                 {
57                         data.Parent = this;
58                         if (data is SectionInfo) {
59                                 if (sections == null) sections = new ConfigInfoCollection ();
60                                 sections [data.Name] = data;
61                         }
62                         else {
63                                 if (groups == null) groups = new ConfigInfoCollection ();
64                                 groups [data.Name] = data;
65                         }
66                 }
67                 
68                 public void Clear ()
69                 {
70                         if (sections != null) sections.Clear ();
71                         if (groups != null) groups.Clear ();
72                 }
73                 
74                 public bool HasChild (string name)
75                 {
76                         if (sections != null && sections [name] != null) return true;
77                         return (groups != null && groups [name] != null);
78                 }
79                 
80                 public void RemoveChild (string name)
81                 {
82                         if (sections != null)
83                                 sections.Remove (name);
84                         if (groups != null)
85                                 groups.Remove (name);
86                 }
87                 
88                 public SectionInfo GetChildSection (string name)
89                 {
90                         if (sections != null)
91                                 return sections [name] as SectionInfo;
92                         else
93                                 return null;
94                 }
95                 
96                 public SectionGroupInfo GetChildGroup (string name)
97                 {
98                         if (groups != null)
99                                 return groups [name] as SectionGroupInfo;
100                         else
101                                 return null;
102                 }
103                 
104                 public ConfigInfoCollection Sections
105                 {
106                         get { if (sections == null) return emptyList; else return sections; }
107                 }
108                 
109                 public ConfigInfoCollection Groups
110                 {
111                         get { if (groups == null) return emptyList; else return groups; }
112                 }
113                 
114                 public override bool HasDataContent (Configuration config)
115                 {
116                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
117                                 foreach (string key in col) {
118                                         ConfigInfo cinfo = col [key];
119                                         if (cinfo.HasDataContent (config))
120                                                 return true;
121                                 }
122                         }
123                         return false;
124                 }
125                 
126                 public override bool HasConfigContent (Configuration cfg)
127                 {
128                         if (StreamName == cfg.FileName) return true;
129                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
130                                 foreach (string key in col) {
131                                         ConfigInfo cinfo = col [key];
132                                         if (cinfo.HasConfigContent (cfg))
133                                                 return true;
134                                 }
135                         }
136                         return false;
137                 }
138                 
139                 public override void ReadConfig (Configuration cfg, string streamName, XmlTextReader reader)
140                 {
141                         StreamName = streamName;
142                         ConfigHost = cfg.ConfigHost;
143                         
144                         if (reader.LocalName != "configSections")
145                         {
146                                 while (reader.MoveToNextAttribute ()) {
147                                         if (reader.Name == "name")
148                                                 Name = reader.Value;
149                                         else if (reader.Name == "type") {
150                                                 TypeName = reader.Value;
151                                                 Type = null;
152                                         }
153                                         else
154                                                 ThrowException ("Unrecognized attribute", reader);
155                                 }
156                                 
157                                 if (Name == null)
158                                         ThrowException ("sectionGroup must have a 'name' attribute", reader);
159         
160                                 if (Name == "location")
161                                         ThrowException ("location is a reserved section name", reader);
162                         }
163                         
164                         if (TypeName == null)
165                                 TypeName = "System.Configuration.ConfigurationSectionGroup";
166                         
167                         if (reader.IsEmptyElement) {
168                                 reader.Skip ();
169                                 return;
170                         }
171                         
172                         reader.ReadStartElement ();
173                         reader.MoveToContent ();
174                         
175                         while (reader.NodeType != XmlNodeType.EndElement)
176                         {
177                                 if (reader.NodeType != XmlNodeType.Element) {
178                                         reader.Skip ();
179                                         continue;
180                                 }
181                                 
182                                 string name = reader.LocalName;
183                                 ConfigInfo cinfo = null;
184                                 
185                                 if (name == "remove") {
186                                         ReadRemoveSection (reader);
187                                         continue;
188                                 }
189
190                                 if (name == "clear") {
191                                         if (reader.HasAttributes)
192                                                 ThrowException ("Unrecognized attribute.", reader);
193
194                                         Clear ();
195                                         reader.Skip ();
196                                         continue;
197                                 }
198
199                                 if (name == "section")
200                                         cinfo = new SectionInfo ();
201                                 else if (name == "sectionGroup")
202                                         cinfo = new SectionGroupInfo ();
203                                 else
204                                         ThrowException ("Unrecognized element: " + reader.Name, reader);
205                                         
206                                 cinfo.ReadConfig (cfg, streamName, reader);
207                                 ConfigInfo actInfo = Groups [cinfo.Name];
208                                 if (actInfo == null) actInfo = Sections [cinfo.Name];
209                                 
210                                 if (actInfo != null) {
211                                         if (actInfo.GetType () != cinfo.GetType ())
212                                                 ThrowException ("A section or section group named '" + cinfo.Name + "' already exists", reader);
213                                         // Make sure that this section is saved in this configuration file:
214                                         actInfo.StreamName = streamName;
215                                 }
216                                 else
217                                         AddChild (cinfo);
218                         }
219                         
220                         reader.ReadEndElement ();
221                 }
222                 
223                 public override void WriteConfig (Configuration cfg, XmlWriter writer, ConfigurationSaveMode mode)
224                 {
225                         if (Name != null) {
226                                 writer.WriteStartElement ("sectionGroup");
227                                 writer.WriteAttributeString ("name", Name);
228                                 if (TypeName != null && TypeName != "" && TypeName != "System.Configuration.ConfigurationSectionGroup")
229                                         writer.WriteAttributeString ("type", TypeName);
230                         }
231                         else
232                                 writer.WriteStartElement ("configSections");
233                         
234                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
235                                 foreach (string key in col) {
236                                         ConfigInfo cinfo = col [key];
237                                         if (cinfo.HasConfigContent (cfg))
238                                                 cinfo.WriteConfig (cfg, writer, mode);
239                                 }
240                         }
241                         
242                         writer.WriteEndElement ();
243                 }
244
245                 private void ReadRemoveSection (XmlTextReader reader)
246                 {
247                         if (!reader.MoveToNextAttribute () || reader.Name != "name")
248                                 ThrowException ("Unrecognized attribute.", reader);
249
250                         string removeValue = reader.Value;
251                         if (removeValue == null || removeValue.Length == 0)
252                                 ThrowException ("Empty name to remove", reader);
253
254                         reader.MoveToElement ();
255
256                         if (!HasChild (removeValue))
257                                 ThrowException ("No factory for " + removeValue, reader);
258
259                         RemoveChild (removeValue);
260                         reader.Skip ();
261                 }
262
263                 public void ReadRootData (XmlTextReader reader, Configuration config, bool overrideAllowed)
264                 {
265                         reader.MoveToContent ();
266                         ReadContent (reader, config, overrideAllowed);
267                 }
268                 
269                 public override void ReadData (Configuration config, XmlTextReader reader, bool overrideAllowed)
270                 {
271                         reader.MoveToContent ();
272                         reader.ReadStartElement ();
273                         ReadContent (reader, config, overrideAllowed);
274                         reader.MoveToContent ();
275                         reader.ReadEndElement ();
276                 }
277                 
278                 void ReadContent (XmlTextReader reader, Configuration config, bool overrideAllowed)
279                 {
280                         StringBuilder spacing = new StringBuilder ();
281                         while (reader.NodeType != XmlNodeType.EndElement) {
282                                 if (reader.NodeType != XmlNodeType.Element) {
283                                         if (reader.NodeType == XmlNodeType.Whitespace)
284                                                 spacing.Append (reader.Value);
285                                         reader.Skip ();
286                                         continue;
287                                 }
288                                 
289                                 if (reader.LocalName == "location")
290                                 {
291                                         if (!config.HasFile)
292                                                 ThrowException ("<location> elements are only allowed in <configuration> elements.", reader);
293                                                  
294                                         string allowOverrideAttr = reader.GetAttribute ("allowOverride");
295                                         bool allowOverride = allowOverrideAttr == null || allowOverrideAttr.Length == 0 || bool.Parse (allowOverrideAttr);
296                                         string path = reader.GetAttribute ("path");
297                                         if (path != null && path.Length > 0) {
298                                                 string xml = reader.ReadOuterXml ();
299                                                 string[] pathList = path.Split (',');
300                                                 foreach (string p in pathList) {
301                                                         ConfigurationLocation loc = new ConfigurationLocation (p.Trim (), xml, config, allowOverride);
302                                                         config.Locations.Add (loc);
303                                                 }
304                                         } else {
305                                                 ReadData (config, reader, allowOverride);
306                                         }
307                                         continue;
308                                 }
309                                 
310                                 ConfigInfo data = (sections != null) ? (ConfigInfo) sections [reader.LocalName] : (ConfigInfo) null;
311                                 if (data == null) data = (groups != null) ? (ConfigInfo) groups [reader.LocalName] : (ConfigInfo) null;
312                                 
313                                 if (data != null)
314                                         data.ReadData (config, reader, overrideAllowed);
315                                 else
316                                         ThrowException ("Unrecognized configuration section <" + reader.LocalName + ">", reader);
317                         }
318                 }
319                 
320                 public void WriteRootData (XmlWriter writer, Configuration config, ConfigurationSaveMode mode)
321                 {
322                         WriteContent (writer, config, mode, false);
323                 }
324                 
325                 public override void WriteData (Configuration config, XmlWriter writer, ConfigurationSaveMode mode)
326                 {
327                         writer.WriteStartElement (Name);
328                         WriteContent (writer, config, mode, true);
329                         writer.WriteEndElement ();
330                 }
331                 
332                 public void WriteContent (XmlWriter writer, Configuration config, ConfigurationSaveMode mode, bool writeElem)
333                 {
334                         foreach (ConfigInfoCollection col in new object[] {Sections, Groups}) {
335                                 foreach (string key in col) {
336                                         ConfigInfo cinfo = col [key];
337                                         if (cinfo.HasDataContent (config))
338                                                 cinfo.WriteData (config, writer, mode);
339                                 }
340                         }
341                 }
342         }
343         
344         internal class ConfigInfoCollection : NameObjectCollectionBase
345         {
346                 public ICollection AllKeys
347                 {
348                         get { return Keys; }
349                 }
350                 
351                 public ConfigInfo this [string name]
352                 {
353                         get { return (ConfigInfo) BaseGet (name); }
354                         set { BaseSet (name, value); }
355                 }
356         
357                 public ConfigInfo this [int index]
358                 {
359                         get { return (ConfigInfo) BaseGet (index); }
360                         set { BaseSet (index, value); }
361                 }
362                 
363                 public void Add (string name, ConfigInfo config)
364                 {
365                         BaseAdd (name, config);
366                 }
367                 
368                 public void Clear ()
369                 {
370                         BaseClear ();
371                 }
372                 
373                 public string GetKey (int index)
374                 {
375                         return BaseGetKey (index);
376                 }
377                 
378                 public void Remove (string name)
379                 {
380                         BaseRemove (name);
381                 }
382                 
383                 public void RemoveAt (int index)
384                 {
385                         BaseRemoveAt (index);
386                 }
387         }
388 }
389
390 #endif