2 // System.Security.SecurityElement.cs
5 // Miguel de Icaza (miguel@ximian.com)
6 // Lawrence Pit (loz@cable.a2000.nl)
7 // Sebastien Pouliot <sebastien@ximian.com>
9 // (C) Ximian, Inc. http://www.ximian.com
10 // Copyright (C) 2004 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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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;
39 namespace System.Security
42 public sealed class SecurityElement
44 internal class SecurityAttribute {
47 private string _value;
49 public SecurityAttribute (string name, string value)
51 if (!IsValidAttributeName (name))
52 throw new ArgumentException (Locale.GetText ("Invalid XML attribute name") + ": " + name);
54 if (!IsValidAttributeValue (value))
55 throw new ArgumentException (Locale.GetText ("Invalid XML attribute value") + ": " + value);
66 get { return _value; }
75 // these values are determined by a simple test program against the MS.Net implementation:
76 // for (int i = 0; i < 256; i++) {
77 // if (!SecurityElement.IsValidTag ("" + ((char) i))) {
78 // System.Console.WriteLine ("TAG: " + i);
81 // note: this is actually an incorrect implementation of MS, as for example the &
82 // character is not a valid character in tag names.
83 private static readonly char [] invalid_tag_chars = new char [] { ' ', '<', '>' };
84 private static readonly char [] invalid_text_chars = new char [] { '<', '>' };
85 private static readonly char [] invalid_attr_name_chars = new char [] { ' ', '<', '>' };
86 private static readonly char [] invalid_attr_value_chars = new char [] { '"', '<', '>' };
87 private static readonly char [] invalid_chars = new char [] { '<', '>', '"', '\'', '&' };
89 public SecurityElement (string tag) : this (tag, null)
93 public SecurityElement (string tag, string text)
99 // not a deep copy (childs are references)
100 internal SecurityElement (SecurityElement se)
105 if (se.attributes != null) {
106 foreach (SecurityAttribute sa in se.attributes) {
107 this.AddAttribute (sa.Name, sa.Value);
110 if (se.children != null) {
111 foreach (SecurityElement child in se.children) {
112 this.AddChild (child);
117 public Hashtable Attributes {
119 if (attributes == null)
122 Hashtable result = new Hashtable (attributes.Count);
123 foreach (SecurityAttribute sa in attributes) {
124 result.Add (sa.Name, sa.Value);
130 if (value == null || value.Count == 0) {
135 if (attributes == null)
136 attributes = new ArrayList ();
139 IDictionaryEnumerator e = value.GetEnumerator ();
140 while (e.MoveNext ()) {
141 attributes.Add (new SecurityAttribute ((string) e.Key, (string) e.Value));
146 public ArrayList Children {
153 foreach (object o in value) {
155 throw new ArgumentNullException ();
156 // shouldn't we also throw an exception
157 // when o isn't an instance of SecurityElement?
170 throw new ArgumentNullException ();
171 if (!IsValidTag (value))
172 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + value);
173 int colon = value.IndexOf (':');
174 tag = colon < 0 ? value : value.Substring (colon + 1);
184 if (!IsValidText (value))
185 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + text);
190 public void AddAttribute (string name, string value)
193 throw new ArgumentNullException ("name");
195 throw new ArgumentNullException ("value");
196 if (GetAttribute (name) != null)
197 throw new ArgumentException (Locale.GetText ("Duplicate attribute : " + name));
199 if (attributes == null)
200 attributes = new ArrayList ();
201 attributes.Add (new SecurityAttribute (name, value));
204 public void AddChild (SecurityElement child)
207 throw new ArgumentNullException ("child");
209 if (children == null)
210 children = new ArrayList ();
212 children.Add (child);
215 public string Attribute (string name)
218 throw new ArgumentNullException ("name");
220 SecurityAttribute sa = GetAttribute (name);
221 return ((sa == null) ? null : sa.Value);
226 public SecurityElement Copy ()
228 return new SecurityElement (this);
232 public bool Equal (SecurityElement other)
240 if (this.text != other.text)
243 if (this.tag != other.tag)
246 if (this.attributes == null && other.attributes != null && other.attributes.Count != 0)
249 if (other.attributes == null && this.attributes != null && this.attributes.Count != 0)
252 if (this.attributes != null && other.attributes != null) {
253 if (this.attributes.Count != other.attributes.Count)
255 foreach (SecurityAttribute sa1 in attributes) {
256 SecurityAttribute sa2 = other.GetAttribute (sa1.Name);
257 if ((sa2 == null) || (sa1.Value != sa2.Value))
262 if (this.children == null && other.children != null && other.children.Count != 0)
265 if (other.children == null && this.children != null && this.children.Count != 0)
268 if (this.children != null && other.children != null) {
269 if (this.children.Count != other.children.Count)
271 for (int i = 0; i < this.children.Count; i++)
272 if (!((SecurityElement) this.children [i]).Equal ((SecurityElement) other.children [i]))
279 public static string Escape (string str)
283 if (str.IndexOfAny (invalid_chars) == -1)
286 sb = new StringBuilder ();
287 int len = str.Length;
289 for (int i = 0; i < len; i++) {
293 case '<': sb.Append ("<"); break;
294 case '>': sb.Append (">"); break;
295 case '"': sb.Append ("""); break;
296 case '\'': sb.Append ("'"); break;
297 case '&': sb.Append ("&"); break;
298 default: sb.Append (c); break;
302 return sb.ToString ();
310 static SecurityElement FromString (string xml)
313 throw new ArgumentNullException ("xml");
315 throw new XmlSyntaxException (Locale.GetText ("Empty string."));
318 SecurityParser sp = new SecurityParser ();
322 catch (Exception e) {
323 string msg = Locale.GetText ("Invalid XML.");
324 throw new XmlSyntaxException (msg, e);
328 public static bool IsValidAttributeName (string name)
330 return name != null && name.IndexOfAny (invalid_attr_name_chars) == -1;
333 public static bool IsValidAttributeValue (string value)
335 return value != null && value.IndexOfAny (invalid_attr_value_chars) == -1;
338 public static bool IsValidTag (string value)
340 return value != null && value.IndexOfAny (invalid_tag_chars) == -1;
343 public static bool IsValidText (string value)
347 return value.IndexOfAny (invalid_text_chars) == -1;
350 public SecurityElement SearchForChildByTag (string tag)
353 throw new ArgumentNullException ("tag");
355 if (this.children == null)
358 for (int i = 0; i < children.Count; i++) {
359 SecurityElement elem = (SecurityElement) children [i];
366 public string SearchForTextOfTag (string tag)
369 throw new ArgumentNullException ("tag");
374 if (this.children == null)
377 for (int i = 0; i < children.Count; i++) {
378 string result = ((SecurityElement) children [i]).SearchForTextOfTag (tag);
386 public override string ToString ()
388 StringBuilder s = new StringBuilder ();
390 return s.ToString ();
393 private void ToXml (ref StringBuilder s, int level)
396 s.Append (' ', level * 3);
401 if (attributes != null) {
405 for (int i=0; i < attributes.Count; i++) {
406 SecurityAttribute sa = (SecurityAttribute) attributes [i];
409 // all other attributes must align with the first one
411 s.Append (' ', (level * 3) + tag.Length + 1);
417 if (i != attributes.Count - 1)
418 s.Append (Environment.NewLine);
422 if ((text == null || text == String.Empty) &&
423 (children == null || children.Count == 0))
424 s.Append ("/>").Append (Environment.NewLine);
426 s.Append (">").Append (text);
427 if (children != null) {
428 s.Append (Environment.NewLine);
429 foreach (SecurityElement child in children) {
430 child.ToXml (ref s, level + 1);
433 s.Append (' ', level * 3);
439 .Append (Environment.NewLine);
443 internal SecurityAttribute GetAttribute (string name)
445 if (attributes != null) {
446 foreach (SecurityAttribute sa in attributes) {