2010-05-27 Jb Evain <jbevain@novell.com>
[mcs.git] / class / corlib / System.Security / SecurityElement.cs
blob9ba34115463047338079e8c56c78cb7d49f2e8f8
1 //
2 // System.Security.SecurityElement.cs
3 //
4 // Authors:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Lawrence Pit (loz@cable.a2000.nl)
7 // Sebastien Pouliot <sebastien@ximian.com>
8 //
9 // (C) Ximian, Inc. http://www.ximian.com
10 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Globalization;
33 using System.Collections;
34 using System.Runtime.InteropServices;
35 using System.Text;
37 using Mono.Xml;
39 namespace System.Security {
41 [ComVisible (true)]
42 [Serializable]
43 public sealed class SecurityElement
45 internal class SecurityAttribute {
47 private string _name;
48 private string _value;
50 public SecurityAttribute (string name, string value)
52 if (!IsValidAttributeName (name))
53 throw new ArgumentException (Locale.GetText ("Invalid XML attribute name") + ": " + name);
55 if (!IsValidAttributeValue (value))
56 throw new ArgumentException (Locale.GetText ("Invalid XML attribute value") + ": " + value);
58 _name = name;
59 _value = SecurityElement.Unescape (value);
62 public string Name {
63 get { return _name; }
66 public string Value {
67 get { return _value; }
71 string text;
72 string tag;
73 ArrayList attributes;
74 ArrayList children;
76 // these values are determined by a simple test program against the MS.Net implementation:
77 // for (int i = 0; i < 256; i++) {
78 // if (!SecurityElement.IsValidTag ("" + ((char) i))) {
79 // System.Console.WriteLine ("TAG: " + i);
80 // }
81 // }
82 // note: this is actually an incorrect implementation of MS, as for example the &
83 // character is not a valid character in tag names.
84 private static readonly char [] invalid_tag_chars = new char [] { ' ', '<', '>' };
85 private static readonly char [] invalid_text_chars = new char [] { '<', '>' };
86 private static readonly char [] invalid_attr_name_chars = new char [] { ' ', '<', '>' };
87 private static readonly char [] invalid_attr_value_chars = new char [] { '"', '<', '>' };
88 private static readonly char [] invalid_chars = new char [] { '<', '>', '"', '\'', '&' };
90 public SecurityElement (string tag) : this (tag, null)
94 public SecurityElement (string tag, string text)
96 if (tag == null)
97 throw new ArgumentNullException ("tag");
98 if (!IsValidTag (tag))
99 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + tag);
100 this.tag = tag;
102 Text = text;
105 // not a deep copy (childs are references)
106 internal SecurityElement (SecurityElement se)
108 this.Tag = se.Tag;
109 this.Text = se.Text;
111 if (se.attributes != null) {
112 foreach (SecurityAttribute sa in se.attributes) {
113 this.AddAttribute (sa.Name, sa.Value);
116 if (se.children != null) {
117 foreach (SecurityElement child in se.children) {
118 this.AddChild (child);
123 public Hashtable Attributes {
124 get {
125 if (attributes == null)
126 return null;
128 Hashtable result = new Hashtable (attributes.Count);
129 foreach (SecurityAttribute sa in attributes) {
130 result.Add (sa.Name, sa.Value);
132 return result;
135 set {
136 if (value == null || value.Count == 0) {
137 attributes.Clear ();
138 return;
141 if (attributes == null)
142 attributes = new ArrayList ();
143 else
144 attributes.Clear ();
145 IDictionaryEnumerator e = value.GetEnumerator ();
146 while (e.MoveNext ()) {
147 attributes.Add (new SecurityAttribute ((string) e.Key, (string) e.Value));
152 public ArrayList Children {
153 get {
154 return children;
157 set {
158 if (value != null) {
159 foreach (object o in value) {
160 if (o == null)
161 throw new ArgumentNullException ();
162 // shouldn't we also throw an exception
163 // when o isn't an instance of SecurityElement?
166 children = value;
170 public string Tag {
171 get {
172 return tag;
174 set {
175 if (value == null)
176 throw new ArgumentNullException ("Tag");
177 if (!IsValidTag (value))
178 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + value);
179 tag = value;
183 public string Text {
184 get {
185 return text;
188 set {
189 if (value != null) {
190 if (!IsValidText (value))
191 throw new ArgumentException (
192 Locale.GetText ("Invalid XML string")
193 + ": " + value);
195 text = Unescape (value);
199 public void AddAttribute (string name, string value)
201 if (name == null)
202 throw new ArgumentNullException ("name");
203 if (value == null)
204 throw new ArgumentNullException ("value");
205 if (GetAttribute (name) != null)
206 throw new ArgumentException (Locale.GetText ("Duplicate attribute : " + name));
208 if (attributes == null)
209 attributes = new ArrayList ();
210 attributes.Add (new SecurityAttribute (name, value));
213 public void AddChild (SecurityElement child)
215 if (child == null)
216 throw new ArgumentNullException ("child");
218 if (children == null)
219 children = new ArrayList ();
221 children.Add (child);
224 public string Attribute (string name)
226 if (name == null)
227 throw new ArgumentNullException ("name");
229 SecurityAttribute sa = GetAttribute (name);
230 return ((sa == null) ? null : sa.Value);
233 [ComVisible (false)]
234 public SecurityElement Copy ()
236 return new SecurityElement (this);
239 public bool Equal (SecurityElement other)
241 if (other == null)
242 return false;
244 if (this == other)
245 return true;
247 if (this.text != other.text)
248 return false;
250 if (this.tag != other.tag)
251 return false;
253 if (this.attributes == null && other.attributes != null && other.attributes.Count != 0)
254 return false;
256 if (other.attributes == null && this.attributes != null && this.attributes.Count != 0)
257 return false;
259 if (this.attributes != null && other.attributes != null) {
260 if (this.attributes.Count != other.attributes.Count)
261 return false;
262 foreach (SecurityAttribute sa1 in attributes) {
263 SecurityAttribute sa2 = other.GetAttribute (sa1.Name);
264 if ((sa2 == null) || (sa1.Value != sa2.Value))
265 return false;
269 if (this.children == null && other.children != null && other.children.Count != 0)
270 return false;
272 if (other.children == null && this.children != null && this.children.Count != 0)
273 return false;
275 if (this.children != null && other.children != null) {
276 if (this.children.Count != other.children.Count)
277 return false;
278 for (int i = 0; i < this.children.Count; i++)
279 if (!((SecurityElement) this.children [i]).Equal ((SecurityElement) other.children [i]))
280 return false;
283 return true;
286 public static string Escape (string str)
288 StringBuilder sb;
290 if (str == null)
291 return null;
293 if (str.IndexOfAny (invalid_chars) == -1)
294 return str;
296 sb = new StringBuilder ();
297 int len = str.Length;
299 for (int i = 0; i < len; i++) {
300 char c = str [i];
302 switch (c) {
303 case '<': sb.Append ("&lt;"); break;
304 case '>': sb.Append ("&gt;"); break;
305 case '"': sb.Append ("&quot;"); break;
306 case '\'': sb.Append ("&apos;"); break;
307 case '&': sb.Append ("&amp;"); break;
308 default: sb.Append (c); break;
312 return sb.ToString ();
315 private static string Unescape (string str)
317 StringBuilder sb;
319 if (str == null)
320 return null;
322 sb = new StringBuilder (str);
323 sb.Replace ("&lt;", "<");
324 sb.Replace ("&gt;", ">");
325 sb.Replace ("&amp;", "&");
326 sb.Replace ("&quot;", "\"");
327 sb.Replace ("&apos;", "'");
328 return sb.ToString ();
331 public static SecurityElement FromString (string xml)
333 if (xml == null)
334 throw new ArgumentNullException ("xml");
335 if (xml.Length == 0)
336 throw new XmlSyntaxException (Locale.GetText ("Empty string."));
338 try {
339 SecurityParser sp = new SecurityParser ();
340 sp.LoadXml (xml);
341 return sp.ToXml ();
342 } catch (Exception e) {
343 string msg = Locale.GetText ("Invalid XML.");
344 throw new XmlSyntaxException (msg, e);
348 public static bool IsValidAttributeName (string name)
350 return name != null && name.IndexOfAny (invalid_attr_name_chars) == -1;
353 public static bool IsValidAttributeValue (string value)
355 return value != null && value.IndexOfAny (invalid_attr_value_chars) == -1;
358 public static bool IsValidTag (string tag)
360 return tag != null && tag.IndexOfAny (invalid_tag_chars) == -1;
363 public static bool IsValidText (string text)
365 return text != null && text.IndexOfAny (invalid_text_chars) == -1;
368 public SecurityElement SearchForChildByTag (string tag)
370 if (tag == null)
371 throw new ArgumentNullException ("tag");
373 if (this.children == null)
374 return null;
376 for (int i = 0; i < children.Count; i++) {
377 SecurityElement elem = (SecurityElement) children [i];
378 if (elem.tag == tag)
379 return elem;
381 return null;
384 public string SearchForTextOfTag (string tag)
386 if (tag == null)
387 throw new ArgumentNullException ("tag");
389 if (this.tag == tag)
390 return this.text;
392 if (this.children == null)
393 return null;
395 for (int i = 0; i < children.Count; i++) {
396 string result = ((SecurityElement) children [i]).SearchForTextOfTag (tag);
397 if (result != null)
398 return result;
401 return null;
404 public override string ToString ()
406 StringBuilder s = new StringBuilder ();
407 ToXml (ref s, 0);
408 return s.ToString ();
411 private void ToXml (ref StringBuilder s, int level)
413 s.Append ("<");
414 s.Append (tag);
416 if (attributes != null) {
417 s.Append (" ");
418 for (int i=0; i < attributes.Count; i++) {
419 SecurityAttribute sa = (SecurityAttribute) attributes [i];
420 s.Append (sa.Name)
421 .Append ("=\"")
422 .Append (Escape (sa.Value))
423 .Append ("\"");
424 if (i != attributes.Count - 1)
425 s.Append (Environment.NewLine);
429 if ((text == null || text == String.Empty) &&
430 (children == null || children.Count == 0))
431 s.Append ("/>").Append (Environment.NewLine);
432 else {
433 s.Append (">").Append (Escape (text));
434 if (children != null) {
435 s.Append (Environment.NewLine);
436 foreach (SecurityElement child in children) {
437 child.ToXml (ref s, level + 1);
439 #if ! NET_2_0
440 s.Append (' ', level * 3);
441 #endif
443 s.Append ("</")
444 .Append (tag)
445 .Append (">")
446 .Append (Environment.NewLine);
450 internal SecurityAttribute GetAttribute (string name)
452 if (attributes != null) {
453 foreach (SecurityAttribute sa in attributes) {
454 if (sa.Name == name)
455 return sa;
458 return null;