2002-06-07 Martin Baulig <martin@gnome.org>
[mono.git] / mcs / class / corlib / System.Security / SecurityElement.cs
1 //
2 // System.Security.SecurityElement.cs
3 //
4 // Author:
5 //   Miguel de Icaza (miguel@ximian.com)
6 //   Lawrence Pit (loz@cable.a2000.nl)
7 //
8 // (C) Ximian, Inc. http://www.ximian.com
9
10 using System.Globalization;
11 using System.Collections;
12 using System.Text;
13
14 namespace System.Security 
15 {
16         [Serializable]
17         public sealed class SecurityElement 
18         {
19                 string text;
20                 string tag;
21                 Hashtable attributes;
22                 ArrayList children;
23                 
24                 // these values are determined by a simple test program against the MS.Net implementation:
25                 //      for (int i = 0; i < 256; i++) {
26                 //              if (!SecurityElement.IsValidTag ("" + ((char) i))) {
27                 //                      System.Console.WriteLine ("TAG: " + i);
28                 //              }
29                 //      }               
30                 // note: this is actually an incorrect implementation of MS, as for example the &
31                 // character is not a valid character in tag names.
32                 private static char [] invalid_tag_chars = new char [] { ' ', '<', '>' };
33                 private static char [] invalid_text_chars = new char [] { '<', '>' };
34                 private static char [] invalid_attr_name_chars = new char [] { ' ', '<', '>' };
35                 private static char [] invalid_attr_value_chars = new char [] { '"', '<', '>' };
36                 private static char [] invalid_chars = new char [] { '<', '>', '"', '\'', '&' };
37                 
38                 public SecurityElement (string tag) : this (tag, null)
39                 {
40                 }
41                 
42                 public SecurityElement (string tag, string text)
43                 {
44                         this.Tag = tag;
45                         this.Text = (text == null) ? String.Empty : text;
46                 }
47                 
48                 public Hashtable Attributes {
49                         get {
50                                 if (attributes == null) 
51                                         return null;
52                                         
53                                 Hashtable result = new Hashtable ();
54                                 IDictionaryEnumerator e = attributes.GetEnumerator ();
55                                 while (e.MoveNext ())
56                                         result.Add (e.Key, e.Value);
57                                 return result;
58                         }
59
60                         set {                           
61                                 if (value == null || value.Count == 0) {
62                                         attributes = null;
63                                         return;
64                                 }
65                                 
66                                 Hashtable result = new Hashtable ();
67                                 IDictionaryEnumerator e = value.GetEnumerator ();
68                                 while (e.MoveNext ()) {
69                                         string key = (string) e.Key;
70                                         string val = (string) e.Value;
71                                         if (!IsValidAttributeName (key))
72                                                 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + key);
73
74                                         if (!IsValidAttributeValue (val))
75                                                 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + key);
76
77                                         result.Add (key, val);
78                                 }
79                                 attributes = result;
80                         }
81                 }
82
83                 public ArrayList Children {
84                         get {
85                                 return children;
86                         }
87
88                         set {
89                                 if (value != null) {
90                                         foreach (object o in value) {
91                                                 if (o == null)
92                                                         throw new ArgumentNullException ();
93                                                 // shouldn't we also throw an exception 
94                                                 // when o isn't an instance of SecurityElement?
95                                         }
96                                 }
97                                 children = value;
98                         }
99                 }
100
101                 public string Tag {
102                         get {
103                                 return tag;
104                         }
105                         set {
106                                 if (value == null)
107                                         throw new ArgumentNullException ();
108                                 if (!IsValidTag (value))
109                                         throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + value);
110                                 tag = value;
111                         }
112                 }
113
114                 public string Text {
115                         get {
116                                 return text;
117                         }
118
119                         set {
120                                 if (!IsValidText (value))
121                                         throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + text);                              
122                                 text = value;
123                         }
124                 }
125
126                 public void AddAttribute (string name, string value)
127                 {
128                         if (name == null || value == null)
129                                 throw new ArgumentNullException ();
130
131                         if (attributes == null)
132                                 attributes = new Hashtable ();
133
134                         //
135                         // The hashtable will throw ArgumentException if name is already there
136                         //
137
138                         if (!IsValidAttributeName (name))
139                                 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + name);
140
141                         if (!IsValidAttributeValue (value))
142                                 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + value);
143                         
144                         attributes.Add (name, value);
145                 }
146
147                 public void AddChild (SecurityElement child)
148                 {
149                         if (child == null)
150                                 throw new ArgumentNullException ();
151
152                         if (children == null)
153                                 children = new ArrayList ();
154
155                         children.Add (child);
156                 }
157
158                 public string Attribute (string name)
159                 {
160                         if (name == null)
161                                 throw new ArgumentNullException ();
162
163                         if (attributes != null)
164                                 return (string) attributes [name];
165                         else
166                                 return null;
167                 }
168
169                 public bool Equal (SecurityElement other)
170                 {
171                         if (other == null)
172                                 return false;
173                                 
174                         if (this == other)
175                                 return true;
176
177                         if (this.text != other.text)
178                                 return false;
179
180                         if (this.tag != other.tag)
181                                 return false;
182
183                         if (this.attributes == null && other.attributes != null && other.attributes.Count != 0)
184                                 return false;
185                                 
186                         if (other.attributes == null && this.attributes != null && this.attributes.Count != 0)
187                                 return false;
188
189                         if (this.attributes != null && other.attributes != null) {
190                                 if (this.attributes.Count != other.attributes.Count) 
191                                         return false;
192                                 IDictionaryEnumerator e = attributes.GetEnumerator ();
193                                 while (e.MoveNext ()) 
194                                         if (other.attributes [e.Key] != e.Value)
195                                                 return false;
196                         }
197                         
198                         if (this.children == null && other.children != null && other.children.Count != 0)
199                                 return false;
200                                         
201                         if (other.children == null && this.children != null && this.children.Count != 0)
202                                 return false;
203                                 
204                         if (this.children != null && other.children != null) {
205                                 if (this.children.Count != other.children.Count)
206                                         return false;
207                                 for (int i = 0; i < this.children.Count; i++) 
208                                         if (!((SecurityElement) this.children [i]).Equal ((SecurityElement) other.children [i]))
209                                                 return false;
210                         }
211                         
212                         return true;
213                 }
214
215                 public static string Escape (string str)
216                 {
217                         StringBuilder sb;
218                         
219                         if (str.IndexOfAny (invalid_chars) == -1)
220                                 return str;
221
222                         sb = new StringBuilder ();
223                         int len = str.Length;
224                         
225                         for (int i = 0; i < len; i++) {
226                                 char c = str [i];
227
228                                 switch (c) {
229                                 case '<':  sb.Append ("&lt;"); break;
230                                 case '>':  sb.Append ("&gt;"); break;
231                                 case '"':  sb.Append ("&quot;"); break;
232                                 case '\'': sb.Append ("&apos;"); break;
233                                 case '&':  sb.Append ("&amp;"); break;
234                                 default:   sb.Append (c); break;
235                                 }
236                         }
237
238                         return sb.ToString ();
239                 }
240
241                 public static bool IsValidAttributeName (string name)
242                 {
243                         return name != null && name.IndexOfAny (invalid_attr_name_chars) == -1;
244                 }
245
246                 public static bool IsValidAttributeValue (string value)
247                 {
248                         return value != null && value.IndexOfAny (invalid_attr_value_chars) == -1;
249                 }
250
251                 public static bool IsValidTag (string value)
252                 {
253                         return value != null && value.IndexOfAny (invalid_tag_chars) == -1;
254                 }
255
256                 public static bool IsValidText (string value)
257                 {
258                         return value != null && value.IndexOfAny (invalid_text_chars) == -1;
259                 }
260
261                 public SecurityElement SearchForChildByTag (string tag) 
262                 {
263                         if (tag == null)
264                                 throw new ArgumentNullException ("tag");
265                                 
266                         if (this.children == null)
267                                 return null;
268                                 
269                         for (int i = 0; i < children.Count; i++) {
270                                 SecurityElement elem = (SecurityElement) children [i];
271                                 if (elem.tag == tag)
272                                         return elem;
273                         }
274                         return null;
275                 }                       
276
277                 public string SearchForTextOfTag (string tag) 
278                 {
279                         if (tag == null)
280                                 throw new ArgumentNullException ("tag");
281                                 
282                         if (this.tag == tag)
283                                 return this.text;
284                                 
285                         if (this.children == null)
286                                 return null;
287                         
288                         for (int i = 0; i < children.Count; i++) {
289                                 string result = ((SecurityElement) children [i]).SearchForTextOfTag (tag);
290                                 if (result != null) 
291                                         return result;
292                         }
293
294                         return null;                    
295                 }
296                 
297                 public override string ToString ()
298                 {
299                         StringBuilder s = new StringBuilder ();
300                         ToXml (ref s, 0);
301                         return s.ToString ();
302                 }
303                 
304                 private void ToXml(ref StringBuilder s, int level)
305                 {
306                         s.Append (' ', level << 2);
307                         s.Append ("<");
308                         s.Append (tag);
309                         
310                         if (attributes != null) {
311                                 IDictionaryEnumerator e = attributes.GetEnumerator ();                          
312                                 while (e.MoveNext ()) {
313                                         s.Append (" ")
314                                          .Append (e.Key)
315                                          .Append ("=\"")
316                                          .Append (e.Value)
317                                          .Append ("\"");
318                                 }
319                         }
320                         
321                         if ((text == null || text == String.Empty) && 
322                             (children == null || children.Count == 0))
323                                 s.Append ("/>");
324                         else {
325                                 s.Append (">").Append (text);
326                                 if (children != null) {
327                                         foreach (SecurityElement child in children) {
328                                                 s.Append (Environment.NewLine);
329                                                 child.ToXml (ref s, level + 1);
330                                         }
331                                 }
332                                 s.Append (Environment.NewLine)
333                                  .Append (' ', level << 2)
334                                  .Append ("</")
335                                  .Append (tag)
336                                  .Append (">");
337                         }
338                 }
339         }
340 }