bring Mono Security to monotouch
[mcs.git] / class / corlib / System.Security / SecurityElement.cs
blob7fd209bd6b7aa0ce3444f55cf6364a9e8df7d12c
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 #if NET_2_0
42 [ComVisible (true)]
43 #endif
44 [Serializable]
45 public sealed class SecurityElement
47 internal class SecurityAttribute {
49 private string _name;
50 private string _value;
52 public SecurityAttribute (string name, string value)
54 if (!IsValidAttributeName (name))
55 throw new ArgumentException (Locale.GetText ("Invalid XML attribute name") + ": " + name);
57 if (!IsValidAttributeValue (value))
58 throw new ArgumentException (Locale.GetText ("Invalid XML attribute value") + ": " + value);
60 _name = name;
61 _value = SecurityElement.Unescape (value);
64 public string Name {
65 get { return _name; }
68 public string Value {
69 get { return _value; }
73 string text;
74 string tag;
75 ArrayList attributes;
76 ArrayList children;
78 // these values are determined by a simple test program against the MS.Net implementation:
79 // for (int i = 0; i < 256; i++) {
80 // if (!SecurityElement.IsValidTag ("" + ((char) i))) {
81 // System.Console.WriteLine ("TAG: " + i);
82 // }
83 // }
84 // note: this is actually an incorrect implementation of MS, as for example the &
85 // character is not a valid character in tag names.
86 private static readonly char [] invalid_tag_chars = new char [] { ' ', '<', '>' };
87 private static readonly char [] invalid_text_chars = new char [] { '<', '>' };
88 private static readonly char [] invalid_attr_name_chars = new char [] { ' ', '<', '>' };
89 private static readonly char [] invalid_attr_value_chars = new char [] { '"', '<', '>' };
90 private static readonly char [] invalid_chars = new char [] { '<', '>', '"', '\'', '&' };
92 public SecurityElement (string tag) : this (tag, null)
96 public SecurityElement (string tag, string text)
98 if (tag == null)
99 throw new ArgumentNullException ("tag");
100 if (!IsValidTag (tag))
101 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + tag);
102 this.tag = tag;
104 Text = text;
107 // not a deep copy (childs are references)
108 internal SecurityElement (SecurityElement se)
110 this.Tag = se.Tag;
111 this.Text = se.Text;
113 if (se.attributes != null) {
114 foreach (SecurityAttribute sa in se.attributes) {
115 this.AddAttribute (sa.Name, sa.Value);
118 if (se.children != null) {
119 foreach (SecurityElement child in se.children) {
120 this.AddChild (child);
125 public Hashtable Attributes {
126 get {
127 if (attributes == null)
128 return null;
130 Hashtable result = new Hashtable (attributes.Count);
131 foreach (SecurityAttribute sa in attributes) {
132 result.Add (sa.Name, sa.Value);
134 return result;
137 set {
138 if (value == null || value.Count == 0) {
139 attributes.Clear ();
140 return;
143 if (attributes == null)
144 attributes = new ArrayList ();
145 else
146 attributes.Clear ();
147 IDictionaryEnumerator e = value.GetEnumerator ();
148 while (e.MoveNext ()) {
149 attributes.Add (new SecurityAttribute ((string) e.Key, (string) e.Value));
154 public ArrayList Children {
155 get {
156 return children;
159 set {
160 if (value != null) {
161 foreach (object o in value) {
162 if (o == null)
163 throw new ArgumentNullException ();
164 // shouldn't we also throw an exception
165 // when o isn't an instance of SecurityElement?
168 children = value;
172 public string Tag {
173 get {
174 return tag;
176 set {
177 if (value == null)
178 throw new ArgumentNullException ("Tag");
179 if (!IsValidTag (value))
180 throw new ArgumentException (Locale.GetText ("Invalid XML string") + ": " + value);
181 tag = value;
185 public string Text {
186 get {
187 return text;
190 set {
191 if (value != null) {
192 if (!IsValidText (value))
193 throw new ArgumentException (
194 Locale.GetText ("Invalid XML string")
195 + ": " + value);
197 text = Unescape (value);
201 public void AddAttribute (string name, string value)
203 if (name == null)
204 throw new ArgumentNullException ("name");
205 if (value == null)
206 throw new ArgumentNullException ("value");
207 if (GetAttribute (name) != null)
208 throw new ArgumentException (Locale.GetText ("Duplicate attribute : " + name));
210 if (attributes == null)
211 attributes = new ArrayList ();
212 attributes.Add (new SecurityAttribute (name, value));
215 public void AddChild (SecurityElement child)
217 if (child == null)
218 throw new ArgumentNullException ("child");
220 if (children == null)
221 children = new ArrayList ();
223 children.Add (child);
226 public string Attribute (string name)
228 if (name == null)
229 throw new ArgumentNullException ("name");
231 SecurityAttribute sa = GetAttribute (name);
232 return ((sa == null) ? null : sa.Value);
235 #if NET_2_0
236 [ComVisible (false)]
237 public SecurityElement Copy ()
239 return new SecurityElement (this);
241 #endif
243 public bool Equal (SecurityElement other)
245 if (other == null)
246 return false;
248 if (this == other)
249 return true;
251 if (this.text != other.text)
252 return false;
254 if (this.tag != other.tag)
255 return false;
257 if (this.attributes == null && other.attributes != null && other.attributes.Count != 0)
258 return false;
260 if (other.attributes == null && this.attributes != null && this.attributes.Count != 0)
261 return false;
263 if (this.attributes != null && other.attributes != null) {
264 if (this.attributes.Count != other.attributes.Count)
265 return false;
266 foreach (SecurityAttribute sa1 in attributes) {
267 SecurityAttribute sa2 = other.GetAttribute (sa1.Name);
268 if ((sa2 == null) || (sa1.Value != sa2.Value))
269 return false;
273 if (this.children == null && other.children != null && other.children.Count != 0)
274 return false;
276 if (other.children == null && this.children != null && this.children.Count != 0)
277 return false;
279 if (this.children != null && other.children != null) {
280 if (this.children.Count != other.children.Count)
281 return false;
282 for (int i = 0; i < this.children.Count; i++)
283 if (!((SecurityElement) this.children [i]).Equal ((SecurityElement) other.children [i]))
284 return false;
287 return true;
290 public static string Escape (string str)
292 StringBuilder sb;
294 if (str == null)
295 return null;
297 if (str.IndexOfAny (invalid_chars) == -1)
298 return str;
300 sb = new StringBuilder ();
301 int len = str.Length;
303 for (int i = 0; i < len; i++) {
304 char c = str [i];
306 switch (c) {
307 case '<': sb.Append ("&lt;"); break;
308 case '>': sb.Append ("&gt;"); break;
309 case '"': sb.Append ("&quot;"); break;
310 case '\'': sb.Append ("&apos;"); break;
311 case '&': sb.Append ("&amp;"); break;
312 default: sb.Append (c); break;
316 return sb.ToString ();
319 private static string Unescape (string str)
321 StringBuilder sb;
323 if (str == null)
324 return null;
326 sb = new StringBuilder (str);
327 sb.Replace ("&lt;", "<");
328 sb.Replace ("&gt;", ">");
329 sb.Replace ("&amp;", "&");
330 sb.Replace ("&quot;", "\"");
331 sb.Replace ("&apos;", "'");
332 return sb.ToString ();
335 #if NET_2_0
336 public
337 #else
338 internal
339 #endif
340 static SecurityElement FromString (string xml)
342 if (xml == null)
343 throw new ArgumentNullException ("xml");
344 if (xml.Length == 0)
345 throw new XmlSyntaxException (Locale.GetText ("Empty string."));
347 try {
348 SecurityParser sp = new SecurityParser ();
349 sp.LoadXml (xml);
350 return sp.ToXml ();
351 } catch (Exception e) {
352 string msg = Locale.GetText ("Invalid XML.");
353 throw new XmlSyntaxException (msg, e);
357 public static bool IsValidAttributeName (string name)
359 return name != null && name.IndexOfAny (invalid_attr_name_chars) == -1;
362 public static bool IsValidAttributeValue (string value)
364 return value != null && value.IndexOfAny (invalid_attr_value_chars) == -1;
367 public static bool IsValidTag (string tag)
369 return tag != null && tag.IndexOfAny (invalid_tag_chars) == -1;
372 public static bool IsValidText (string text)
374 return text != null && text.IndexOfAny (invalid_text_chars) == -1;
377 public SecurityElement SearchForChildByTag (string tag)
379 if (tag == null)
380 throw new ArgumentNullException ("tag");
382 if (this.children == null)
383 return null;
385 for (int i = 0; i < children.Count; i++) {
386 SecurityElement elem = (SecurityElement) children [i];
387 if (elem.tag == tag)
388 return elem;
390 return null;
393 public string SearchForTextOfTag (string tag)
395 if (tag == null)
396 throw new ArgumentNullException ("tag");
398 if (this.tag == tag)
399 return this.text;
401 if (this.children == null)
402 return null;
404 for (int i = 0; i < children.Count; i++) {
405 string result = ((SecurityElement) children [i]).SearchForTextOfTag (tag);
406 if (result != null)
407 return result;
410 return null;
413 public override string ToString ()
415 StringBuilder s = new StringBuilder ();
416 ToXml (ref s, 0);
417 return s.ToString ();
420 private void ToXml (ref StringBuilder s, int level)
422 #if ! NET_2_0
423 s.Append (' ', level * 3);
424 #endif
425 s.Append ("<");
426 s.Append (tag);
428 if (attributes != null) {
429 #if NET_2_0
430 s.Append (" ");
431 #endif
432 for (int i=0; i < attributes.Count; i++) {
433 SecurityAttribute sa = (SecurityAttribute) attributes [i];
434 #if ! NET_2_0
435 s.Append (" ");
436 // all other attributes must align with the first one
437 if (i != 0)
438 s.Append (' ', (level * 3) + tag.Length + 1);
439 #endif
440 s.Append (sa.Name)
441 .Append ("=\"")
442 .Append (Escape (sa.Value))
443 .Append ("\"");
444 if (i != attributes.Count - 1)
445 s.Append (Environment.NewLine);
449 if ((text == null || text == String.Empty) &&
450 (children == null || children.Count == 0))
451 s.Append ("/>").Append (Environment.NewLine);
452 else {
453 s.Append (">").Append (Escape (text));
454 if (children != null) {
455 s.Append (Environment.NewLine);
456 foreach (SecurityElement child in children) {
457 child.ToXml (ref s, level + 1);
459 #if ! NET_2_0
460 s.Append (' ', level * 3);
461 #endif
463 s.Append ("</")
464 .Append (tag)
465 .Append (">")
466 .Append (Environment.NewLine);
470 internal SecurityAttribute GetAttribute (string name)
472 if (attributes != null) {
473 foreach (SecurityAttribute sa in attributes) {
474 if (sa.Name == name)
475 return sa;
478 return null;